1

我想知道是否可以取消 Web 请求或向ReverseProxy.Director函数内部的客户端发送内部响应。

假设我们做了一些引发错误的事情,或者我们有其他理由不转发请求。

proxy := &httputil.ReverseProxy{
    Director: func(r *http.Request) {
        err := somethingThatThrows()
    },
}

http.Handle("/", proxy)

对此的解决方案可能如下,但它不像上述使用代理的方式那么简洁。我也不确定应该以这种方式修改请求的程度。导演似乎是这样做的地方。

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    err := somethingThatThrows()
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }
    proxy.ServeHTTP(w, r)
})
4

1 回答 1

1

如果可以取消网络请求 [...]

您可以取消传递给Director函数的请求,有一些细节需要考虑:

  • 取消请求的正确方法是取消其上下文
  • 您不能取消您自己没有设置 (deadline|timeout|cancelfunc) 的上下文 → 即您必须有权访问该cancel功能 → 即您不能取消其他人创建的父上下文。
  • *http.Request传递给Director函数是原始请求的克隆

基于以上几点,您可以将 中的请求替换为Director另一个具有可取消上下文的请求。它可能如下所示:

proxy := &httputil.ReverseProxy{
    Director: func(req *http.Request) {

        // create a cancellable context, and re-set the request
        ctx, cancel := context.WithCancel(req.Context())
        *req = *req.WithContext(ctx)

        err := somethingThatThrows()
        if err != nil {
            cancel()
            return
        }
    },
}

然后上面的代码本身不会做任何其他事情。应该发生的是,在实际向上游服务发送任何内容之前httputil.ReverseProxy.Transport,实现检查请求上下文是否被取消的函数。http.RoundTripper

国家的文件Director

Director 必须是将请求修改为要使用 Transport 发送的新请求的函数。

如果Transport未提供 ,它将回退到 ,这会http.DefaultTransport在取消上下文时中止请求。当前代码(Go 1.17.5)如下所示:

        select {
        case <-ctx.Done():
            req.closeBody()
            return nil, ctx.Err()
        default:
        }

如果您提供自己的实现,http.RoundTripper您可能希望自己实现该行为。还要记住,上下文完成通道是nil如果它不可取消,所以你必须设置一个取消函数并调用cancel(),以便select让它运行“完成”情况。


或向 ReverseProxy.Director 内的客户端发送内部响应

基于上面文档的相同引用,您不应该函数内写入http.ResponseWriterfrom Director——假设您甚至关闭它。如您所见,Director它本身并没有http.ResponseWriter作为参数,这应该已经是一个不言自明的细节。

如果您想在无法转发请求的情况下指定一些其他行为,并假设在取消 req 上下文时http.RoundTripper返回的任何实现,您可以提供您的函数:errorReverseProxy.ErrorHandler

proxy.ErrorHandler = func(writer http.ResponseWriter, request *http.Request, err error) {
    // inspect err
    // write to writer
}

将在返回错误时ErrorHandler调用Transport,包括当错误来自取消的请求时,并且它确实有http.ResponseWriter作为参数。

于 2022-02-09T08:13:56.300 回答