event.passThroughOnException 向源发送请求,但没有 POST 数据

event.passThroughOnException sends requests to origin, but without POST data

我认为 event.passThroughOnException(); 应该为我的工作人员设置 fail open 策略,这样如果我的代码出现异常,原始请求就会发送到我的源服务器,但似乎它缺少 post 数据。我认为这是因为请求体是一个可读流,一旦读取就无法再次读取,但是如何管理这种情况?

addEventListener('fetch', (event) => {
  event.passThroughOnException();
  event.respondWith(handleRequest(event));
});

async function handleRequest(event: FetchEvent): Promise<Response> {
  const response = await fetch(event.request);

  // do something here that potentially raises an Exception
  // @ts-ignore
  ohnoez(); // deliberate failure

  return response;
}

如下图所示,源服务器没有收到任何正文(foobar):

不幸的是,这是 passThroughOnException() 的已知限制。 Workers Runtime 对请求和响应主体使用流;它不会缓冲 body。结果,body 一旦被消耗,它就没有了。所以如果你转发请求,然后抛出异常,请求body就不能再发送了。

通过克隆 event.request 来解决问题,然后在 handleRequest 中添加 try/catch。在 catch(err) 上,使用 fetch 将请求发送到源,同时传递克隆的请求。


// Pass request to whatever it requested
async function passThrough(request: Request): Promise<Response> {
  try {
    let response = await fetch(request)

    // Make the headers mutable by re-constructing the Response.
    response = new Response(response.body, response)
    return response
  } catch (err) {
    return ErrorResponse.NewError(err).respond()
  }
}

// request handler
async function handleRequest(event: FetchEvent): Promise<Response> {
  const request = event.request
  const requestClone = event.request.clone()
  let resp

  try {
    // handle request
    resp = await handler.api(request)

  } catch (err) {
    // Pass through manually on exception (because event.passThroughOnException
    // does not pass request body, so use that as a last resort)
    resp = await passThrough(requestClone)
  }

  return resp
}


addEventListener('fetch', (event) => {
  // Still added passThroughOnException here 
  // in case the `passThrough` function throws exception
  event.passThroughOnException()
  event.respondWith(handleRequest(event))
})

到目前为止似乎工作正常。很想知道是否还有其他解决方案。