Spec-Zone.ru › Deno 2

API веб-платформы

Один из способов, которым Deno упрощает разработку веб- и облачных приложений, заключается в использовании стандартных API веб-платформы (например, fetch, WebSockets и других) вместо проприетарных API. Это означает, что если вы когда-либо разрабатывали для браузера, вам, вероятно, уже знакомо Deno, а если вы изучаете Deno, вы также расширяете свои знания о веб-технологиях.

Изучить поддерживаемые веб-API

Ниже мы рассмотрим некоторые стандартные веб-API, которые поддерживает Deno.

Чтобы проверить, доступен ли API веб-платформы в Deno, вы можете перейти по ссылке на интерфейс на MDN и обратиться к таблице совместимости с браузерами.

fetch

API fetch может использоваться для отправки HTTP-запросов. Он реализован в соответствии со спецификацией WHATWG fetch.

Отклонения от спецификации

  • У пользователя Deno нет хранилища cookie. Следовательно, заголовок set-cookie в ответе не обрабатывается и не отфильтровывается из видимых заголовков ответа.
  • Deno не следует политике одного происхождения, поскольку у агента пользователя Deno в настоящее время нет понятия происхождения и нет хранилища cookie. Это означает, что Deno не нужно защищать от утечки аутентифицированных данных через разные источники. По этой причине Deno не реализует следующие разделы спецификации WHATWG fetch:
    • Раздел 3.1. 'Origin' header.
    • Раздел 3.2. CORS protocol.
    • Раздел 3.5. CORB.
    • Раздел 3.6. 'Cross-Origin-Resource-Policy' header.
    • Atomic HTTP redirect handling.
    • Тип ответа opaqueredirect.
  • fetch с режимом redirect manual вернет ответ basic, а не opaqueredirect.
  • В спецификации неясно, как обрабатывать file: URL-адреса. Firefox — единственный распространенный браузер, который реализует получение file: URL-адресов, и даже тогда это не работает по умолчанию. Начиная с Deno 1.16, Deno поддерживает загрузку локальных файлов. Подробности см. в следующем разделе.
  • Защита заголовков request и response реализована, но, в отличие от браузеров, не имеет ограничений на разрешенные имена заголовков.
  • Свойства referrer, referrerPolicy, mode, credentials, cache, integrity, keepalive, и window и их соответствующие поведения в RequestInit не реализованы. Соответствующие поля отсутствуют в объекте Request.
  • Поддержка потоковой передачи загрузки тела запроса (в HTTP/1.1 и HTTP/2). В отличие от текущего предложения fetch, реализация поддерживает двунаправленную потоковую передачу.
  • Заголовок set-cookie не конкатенируется при итерации по итератору headers . Это поведение находится в процессе спецификации на стадии спецификации.

Загрузка локальных файлов

Deno поддерживает загрузку file: URL-адресов. Это упрощает написание кода, который использует один и тот же путь кода на сервере и локально, а также упрощает создание кода, который работает как с Deno CLI, так и с Deno Deploy.

Deno поддерживает только абсолютные URL-адреса файлов, это означает, что fetch("./some.json") не будет работать. Тем не менее, следует отметить, что если указан --location, относительные URL-адреса используют --location в качестве базового, но file: URL не может быть передан в качестве --location.

Для загрузки ресурса, относительного к текущему модулю, который будет работать как локально, так и удаленно, следует использовать import.meta.url в качестве базового. Например:

const response = await fetch(new URL("./config.json", import.meta.url));
const config = await response.json();

Примечания по загрузке локальных файлов:

  • Для чтения ресурсов применяются разрешения, поэтому необходимо соответствующее разрешение --allow-read для чтения локального файла.
  • Локальная загрузка поддерживает только метод GET, а любой другой метод отклонит обещание.
  • Файла, которого не существует, просто отклоняет обещание с неясным сообщением TypeError. Это сделано для предотвращения потенциальных атак на определение.
  • В ответе не задаются заголовки. Поэтому потребителю необходимо самостоятельно определять такие вещи, как тип содержимого или длина содержимого.
  • Тела ответов передаются потоком со стороны Rust, поэтому большие файлы доступны по частям и могут быть отменены.

CustomEvent и EventTarget

API DOM Event можно использовать для отправки и прослушивания событий, происходящих в приложении. Он реализован в соответствии со спецификацией WHATWG DOM.

Отклонения от спецификации

  • События не распространяются, так как у Deno нет иерархии DOM, поэтому нет дерева для распространения/захвата событий.
  • Свойство timeStamp всегда устанавливается в значение 0.

Типизация

Определения TypeScript для реализованных веб-API можно найти в файлах lib.deno.shared_globals.d.ts и lib.deno.window.d.ts.

Определения, специфичные для рабочих процессов, можно найти в файле lib.deno.worker.d.ts.

Location

Deno поддерживает глобальный объект location из веб-среды.

Флаг Location

В процессе Deno нет «веб-страницы», URL которой мы можем использовать для расположения. Вместо этого мы позволяем пользователям эмулировать расположение документа, указав его в командной строке с флагом --location. Это может быть http или https URL-адрес.

// deno run --location https://example.com/path main.ts

console.log(location.href);
// "https://example.com/path"

Для работы необходимо передать --location <href> . Если этого не сделать, любой доступ к глобальному объекту location вызовет ошибку.

// deno run main.ts

console.log(location.href);
// error: Uncaught ReferenceError: Access to "location", run again with --location <href>.

Установка location или любого из его полей обычно вызывает навигацию в браузерах. Это не применимо в Deno, поэтому в этом случае будет выброшена ошибка.

// deno run --location https://example.com/path main.ts

location.pathname = "./foo";
// error: Uncaught NotSupportedError: Cannot set "location.pathname".

Расширенное использование

В веб-среде разрешение ресурсов (за исключением модулей) обычно использует значение location.href в качестве корня для базирования относительных URL-адресов. Это влияет на некоторые веб-API, принятые Deno.

API fetch

// deno run --location https://api.github.com/ --allow-net main.ts

const response = await fetch("./orgs/denoland");
// Fetches "https://api.github.com/orgs/denoland".

Вызов fetch() выше выбросит ошибку, если не был передан флаг --location, поскольку нет аналога веб-расположения для его базирования.

Модули рабочих процессов

// deno run --location https://example.com/index.html --allow-net main.ts

const worker = new Worker("./workers/hello.ts", { type: "module" });
// Fetches worker module at "https://example.com/workers/hello.ts".
Примечание

Для вышеперечисленных случаев предпочтительнее передавать URL-адреса полностью, а не полагаться на --location. При необходимости вы можете вручную создать относительный URL-адрес с помощью конструктора URL.

Флаг --location предназначен для тех, кто преследует определенную цель эмуляции расположения документа и понимает, что это будет работать только на уровне приложения. Однако вы также можете использовать его для подавления ошибок от зависимостей, которые без необходимости обращаются к глобальному объекту location.

Web Storage

API Web Storage предоставляет API для хранения строковых ключей и значений. Сохранение данных работает аналогично браузеру и имеет лимит хранения 10 МБ. Глобальный объект sessionStorage сохраняет данные только для текущего контекста выполнения, в то время как localStorage сохраняет данные от выполнения к выполнению.

В браузере localStorage сохраняет данные уникально для каждого происхождения (по сути, протокол плюс имя хоста плюс порт). Начиная с Deno 1.16, Deno имеет набор правил для определения уникального места хранения данных:

  • При использовании флага --location, происхождение расположения используется для уникального хранения данных. Это означает, что расположения http://example.com/a.ts, http://example.com/b.ts и http://example.com:80/ будут использовать одно и то же хранилище, но https://example.com/ будет другим.
  • Если указатель расположения отсутствует, но указан файл конфигурации --config, абсолютный путь к этому файлу конфигурации используется. Это означает, что deno run --config deno.jsonc a.ts и deno run --config deno.jsonc b.ts будут использовать одно и то же хранилище, но deno run --config tsconfig.json a.ts будет другим.
  • Если нет файла конфигурации или указателя расположения, Deno использует абсолютный путь к главному модулю для определения общего хранилища. Deno REPL генерирует «синтетический» главный модуль, основанный на текущей рабочей директории, из которой запускается deno . Это означает, что несколько запусков REPL из одного пути будут использовать одни и те же сохраненные данные localStorage.

Для установки, получения и удаления элементов из localStorage, можно использовать следующее:

// Set an item in localStorage
localStorage.setItem("myDemo", "Deno App");

// Read an item from localStorage
const cat = localStorage.getItem("myDemo");

// Remove an item from localStorage
localStorage.removeItem("myDemo");

// Remove all items from localStorage
localStorage.clear();

Web Workers

Deno поддерживает Web Worker API.

Рабочие процессы могут использоваться для запуска кода на нескольких потоках. Каждый экземпляр Worker выполняется в отдельном потоке, предназначенном только для этого рабочего процесса.

В настоящее время Deno поддерживает только рабочие процессы типа module, поэтому при создании нового рабочего процесса необходимо передать опцию type: "module".

Использование относительных указателей модулей в главном рабочем процессе поддерживается только при передаче --location <href> в командной строке. Это не рекомендуется для переносимости. Вместо этого можно использовать конструктор URL и import.meta.url для лёгкого создания указателя для ближайшего скрипта. Однако у выделенных рабочих процессов есть расположение и эта возможность по умолчанию.

// Good
new Worker(import.meta.resolve("./worker.js"), { type: "module" });

// Bad
new Worker(import.meta.resolve("./worker.js"));
new Worker(import.meta.resolve("./worker.js"), { type: "classic" });
new Worker("./worker.js", { type: "module" });

Как и для обычных модулей, в модулях рабочих процессов можно использовать верхнеуровневые await. Однако следует быть осторожным и всегда регистрировать обработчик сообщений до первого await, так как в противном случае сообщения могут быть потеряны. Это не ошибка Deno, а всего лишь неприятное взаимодействие функций, и это также происходит во всех браузерах, поддерживающих модульные рабочие процессы.

import { delay } from "jsr:@std/async@1/delay";

// First await: waits for a second, then continues running the module.
await delay(1000);

// The message handler is only set after that 1s delay, so some of the messages
// that reached the worker during that second might have been fired when no
// handler was registered.
self.onmessage = (evt) => {
  console.log(evt.data);
};

Разрешения на создание экземпляров

Создание нового Worker экземпляра похоже на динамический импорт; поэтому Deno требует соответствующих разрешений для этого действия.

Для рабочих процессов, использующих локальные модули; требуется разрешение --allow-read.

main.ts
new Worker(import.meta.resolve("./worker.ts"), { type: "module" });
worker.ts
console.log("hello world");
self.close();
$ deno run main.ts
error: Uncaught PermissionDenied: read access to "./worker.ts", run again with the --allow-read flag

$ deno run --allow-read main.ts
hello world

Для рабочих процессов, использующих удалённые модули; требуется разрешение --allow-net.

main.ts
new Worker("https://example.com/worker.ts", { type: "module" });
worker.ts
// This file is hosted at https://example.com/worker.ts
console.log("hello world");
self.close();
$ deno run main.ts
error: Uncaught PermissionDenied: net access to "https://example.com/worker.ts", run again with the --allow-net flag

$ deno run --allow-net main.ts
hello world

Использование Deno в рабочем процессе

main.js
const worker = new Worker(import.meta.resolve("./worker.js"), {
  type: "module",
});

worker.postMessage({ filename: "./log.txt" });
worker.js
self.onmessage = async (e) => {
  const { filename } = e.data;
  const text = await Deno.readTextFile(filename);
  console.log(text);
  self.close();
};
log.txt
hello world
$ deno run --allow-read main.js
hello world

Указание разрешений для рабочего процесса

Внимание

Это нестабильная функция Deno. Узнайте больше о нестабильных функциях.

Разрешения, доступные для рабочего процесса, аналогичны флагам разрешений командной строки, что означает, что каждое включенное разрешение можно отключить на уровне API рабочего процесса. Более подробное описание каждого из параметров разрешений можно найти здесь.

По умолчанию рабочий процесс наследует разрешения из потока, в котором он был создан, однако для ограничения доступа этого рабочего процесса мы предоставляем опцию deno.permissions в API рабочего процесса.

Для разрешений, которые поддерживают гранулированный доступ, вы можете передать список требуемых ресурсов, к которым будет иметь доступ рабочий процесс, а для тех, которые поддерживают только включение/выключение, вы можете передать true/false соответственно:

const worker = new Worker(import.meta.resolve("./worker.js"), {
  type: "module",
  deno: {
    permissions: {
      net: [
        "deno.land",
      ],
      read: [
        new URL("./file_1.txt", import.meta.url),
        new URL("./file_2.txt", import.meta.url),
      ],
      write: false,
    },
  },
});

Разрешения с гранулированным доступом принимают абсолютные и относительные пути в качестве аргументов, однако следует учитывать, что относительные пути будут разрешаться относительно файла, в котором создаётся рабочий процесс, а не пути к файлу самого рабочего процесса:

const worker = new Worker(
  new URL("./worker/worker.js", import.meta.url).href,
  {
    type: "module",
    deno: {
      permissions: {
        read: [
          "/home/user/Documents/deno/worker/file_1.txt",
          "./worker/file_2.txt",
        ],
      },
    },
  },
);

Как deno.permissions, так и его дочерние элементы поддерживают опцию "inherit", что подразумевает, что они унаследуют разрешения своего родительского элемента:

// This worker will inherit its parent permissions
const worker = new Worker(import.meta.resolve("./worker.js"), {
  type: "module",
  deno: {
    permissions: "inherit",
  },
});
// This worker will inherit only the net permissions of its parent
const worker = new Worker(import.meta.resolve("./worker.js"), {
  type: "module",
  deno: {
    permissions: {
      env: false,
      hrtime: false,
      net: "inherit",
      ffi: false,
      read: false,
      run: false,
      write: false,
    },
  },
});

Если не указана опция deno.permissions или один из её дочерних элементов, рабочий процесс по умолчанию наследует разрешения:

// This worker will inherit its parent permissions
const worker = new Worker(import.meta.resolve("./worker.js"), {
  type: "module",
});
// This worker will inherit all the permissions of its parent BUT net
const worker = new Worker(import.meta.resolve("./worker.js"), {
  type: "module",
  deno: {
    permissions: {
      net: false,
    },
  },
});

Вы можете полностью отключить разрешения рабочего процесса, передав "none" опции deno.permissions.

// This worker will not have any permissions enabled
const worker = new Worker(import.meta.resolve("./worker.js"), {
  type: "module",
  deno: {
    permissions: "none",
  },
});

Отклонения других API от спецификации

API кэша

Реализованы только следующие API:

  • CacheStorage::open()
  • CacheStorage::has()
  • CacheStorage::delete()
  • Cache::match()
  • Cache::put()
  • Cache::delete()

Несколько отличий по сравнению с браузерами:

  1. Вы не можете передавать относительные пути в API. Запрос может быть экземпляром Request или URL или строкой URL.
  2. match() и delete() пока не поддерживают параметры запроса.

© 2018–2024 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/runtime/reference/web_platform_apis

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API