Как я могу сделать Cloudflare рабочим, который перезаписывает код состояния ответа, но сохраняет остальную часть ответа?

В частности, меня интересует изменение всех ответов с кодом 403 на код 404 и изменение всех ответов с кодом 301 на 302. Я не хочу, чтобы изменялась любая другая часть ответа, кроме текста статуса (который я хочу оставить пустым), Ниже моя собственная попытка этого:

addEventListener("fetch", event => {
  event.respondWith(fetchAndModify(event.request));
});

async function fetchAndModify(request) {
  // Send the request on to the origin server.
  const response = await fetch(request);

  const body = await response.body
  newStatus = response.status
  if (response.status == 403) {
    newStatus = 404
  } else if (response.status == 301) {
    newStatus = 302
  }

  // Return modified response.
  return new Response(body, {
    status: newStatus,
    statusText: "",
    headers: response.headers
  });
}

Я подтвердил, что этот код работает. Я хотел бы знать, существует ли вообще какая-либо возможность, что это перезаписывает часть ответа, кроме кода состояния или текста, и если да, то как я могу избежать этого? Если это противоречит определенным рекомендациям работников Cloudflare или javascript, опишите, какие и почему.

1 ответ

Решение

Вы наткнулись на реальную проблему со спецификацией Fetch API, как она написана сегодня.

На данный момент, status, statusText, а также headers являются единственными стандартными свойствами структуры инициализации Response. Однако нет гарантии, что они навсегда останутся единственными свойствами, и нет гарантии, что реализация не предоставляет дополнительных нестандартных или еще не стандартных свойств.

Фактически, Cloudflare Workers сегодня реализует нестандартное свойство: webSocket, который используется для реализации проксирования WebSocket. Это свойство присутствует, если запрос передан fetch() был запрос инициирования WebSocket, и сервер-источник завершил рукопожатие WebSocket. В этом случае, если вы уроните webSocket поле из Response, Проксирование WebSocket сломается - что может иметь или не иметь значение для вас.

К сожалению, стандарт не определяет какой-либо хороший способ переписать одно свойство Response без потенциальной потери непредвиденных свойств. Это отличается от Request объекты, которые предлагают (несколько неловкий) способ сделать такие переписывания: Requestконструктор может занять другое Request Объект в качестве первого параметра, в этом случае второй параметр указывает только свойства для изменения. Альтернативно, чтобы изменить только URL, вы можете передать URL в качестве первого параметра и Request объект как второй параметр. Это работает, потому что Request объект оказывается той же "формы", что и структура инициализатора конструктора (неясно, намеревались ли это авторы спецификаций или это был счастливый случай). Exmaples:

// change URL
request = new Request(newUrl, request);

// change method (or any other property)
request = new Request(request, {method: "GET"});

Но для ResponseВы не можете передать существующий Response объект в качестве первого параметра Responseконструктор. Есть простые способы изменить тело и заголовки:

// change response body
response = new Response(newBody, response);

// change response headers
// Making a copy of a Response object makes headers mutable.
response = new Response(response.body, response);
response.headers.set("Foo", "bar");

Но если вы хотите изменить status... можно сделать трюк, но это не красиво:

// Create an initializer by copying the Response's enumerable fields
// into a new object.
let init = {...response};

// Modify it.
init.status = 404;
init.statusText = "Not Found";

// Work around a bug where `webSocket` is `null` but needs to be `undefined`.
// (Sorry, I only just noticed this when testing this answer! We'll fix this
// in the future.)
init.webSocket = init.webSocket || undefined;

// Create a new Response.
response = new Response(response.body, init);

Но, конечно, это было ужасно.

Я предложил улучшения для API Fetch, чтобы решить эту проблему, но у меня еще не было времени их выполнить.:(

Другие вопросы по тегам