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

问题描述

我认为event.passthroughOnException();应该为我的工作人员设置fail open策略,这样,如果从我的代码中引发异常,原始请求将发送到我的原始服务器,但似乎丢失了发布数据。我认为这是因为请求正文是可读的流,一旦读取就无法再次读取,但是如何管理这种情况?

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):

example in worker playground

解决方法

不幸的是,这是passThroughOnException()的已知限制。工人运行时使用流作为请求和响应主体;它不会缓冲身体。结果,一旦身体被消耗掉,它就消失了。因此,如果转发请求,然后再引发异常,则请求正文将无法再次发送。

,

通过克隆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))
})

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