当前位置: 首页 > 面试题库 >

使用自定义的http.ResponseWriter基于代理请求的响应编写cookie?

凤高翰
2023-03-14
问题内容

我在这里原来的问题被标记为该问题的重复。我没有实现它的运气,并且怀疑我的问题被误解了,所以在我的问题结束时,我从一个更具体的问题开始着手。

我正在尝试基于中间代理中响应代理的响应标头设置cookie,该请求被反向代理。

这是工作流程:

  • 用户请求http://example.com/foo/bar
  • Go应用使用ReverseProxy将请求转发到http://baz.com
  • baz.com设置响应头 X-FOO
  • Go app通过设置MYAPPFOO带有X-FOO响应标头值的cookie来修改响应
  • Cookie被写入用户的浏览器

有人建议,可以使用自定义http.ResponseWriter方式,但是在尝试并搜索更多信息后,尚不清楚如何实现此目的。

由于我无法掌握用例的自定义ResponseWriter的概念,因此我将发布代码,以更精确地演示我在遇到困难时试图做的事情:

package main

import (

    "github.com/gorilla/mux"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
)

func setCookie(w http.ResponseWriter, name string, value string) {
    ...
    http.SetCookie(w, &cookie)
}

func handler(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        // setCookie() works here
        // but I cannot access w.Header().Get("X-FOO")

        next.ServeHTTP(w, r)

        // I can access w.Header().Get("X-FOO") here
        // but setCookie() does not cookie the user's browser

        // If I could do it all in one place, this is what I would do:
        if r.Method == "POST" && r.URL.String() == "/login" {
            foo := w.Header().Get("X-FOO")
            setCookie(w, "MYAPPFOO", foo)

        }
    })
}

func main() {

    r := mux.NewRouter()
    r.Use(handler)
    proxy := httputil.NewSingleHostReverseProxy("https://baz.example.com/")
    r.PathPrefix("/").Handler(proxy)
    log.Fatal(http.ListenAndServe(":9001", r))
}

附带说明一下,我能够按照ReverseProxy.ModifyResponse上一个问题的注释中的建议进行这项工作,但我真的很想用中间件来实现这一点,以保持从配置中动态创建代理的代码干净。(不在示例代码中)


问题答案:

从有关http.ResponseWriter方法的文档中:(
添加了重点)

  • Header() http.Header

除非修改后的标头是预告片,否则在 调用WriteHeader(或Write)后 更改标头映射 无效

  • WriteHeader(statusCode int)

WriteHeader 发送 带有提供的状态代码 的HTTP响应标头

  • Write([]byte) (int, error)

如果尚未 调用WriteHeader ,则Write 在写入数据之前会 调用WriteHeader(http.StatusOK)

这应该强调为什么,你不能设置在后一个cookie的原因next.ServeHTTP(w, r)调用,这是在通过电话执行的中间件链中的处理程序中的一个或者打电话WriteHeaderWrite直接或间接的。

因此,要能够在调用 之后 设置cookie next.ServeHTTP(w, r)您需要确保中间件链调用WriteHeaderWrite原始http.ResponseWriter实例中没有任何处理程序。一种方法是将原始实例包装在自定义http.ResponseWriter实现中,该实现将
推迟 响应的编写,直到完成cookie设置为止。

例如这样的事情:

type responsewriter struct {
    w    http.ResponseWriter
    buf  bytes.Buffer
    code int
}

func (rw *responsewriter) Header() http.Header {
    return rw.w.Header()
}

func (rw *responsewriter) WriteHeader(statusCode int) {
    rw.code = statusCode
}

func (rw *responsewriter) Write(data []byte) (int, error) {
    return rw.buf.Write(data)
}

func (rw *responsewriter) Done() (int64, error) {
    if rw.code > 0 {
        rw.w.WriteHeader(rw.code)
    }
    return io.Copy(rw.w, &rw.buf)
}

您可以在中间件中像这样使用它:

func handler(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        rw := &responsewriter{w: w}
        next.ServeHTTP(rw, r)

        if r.Method == "POST" && r.URL.String() == "/login" {
            foo := rw.Header().Get("X-FOO")
            setCookie(rw, "MYAPPFOO", foo)
        }

        if _, err := rw.Done(); err != nil {
            log.Println(err)
        }
    })
}


 类似资料:
  • 我通过endpoint与我的laravel服务器通话。我不使用Laravel View,因此无法访问其会话。 当一个需要的请求进来,我需要返回一个响应即etc每个参数?可能吗? 内部: 如果我应该使用字符串消息,而不是laravel重定向没有响应,我使用邮递员,我看到状态200。如何实现我想要的?我想用响应自定义每个必需的参数。

  • 我是Scala的新手。 我在用加特林做压力测试。 我能够进行一个Gatling测试,向WS发出请求,我将JSON响应保存在session变量中。响应是一个JSON数组,其中包含指向我的后端提供的图像的多个链接。 具体来说,第一个请求检索地图中的点,每个点都分配了一个图像,必须通过访问第一个WS响应提供的链接来获取每个图像。 我有以下代码: 第一个WS的JSON响应示例: 第一个请求工作正常,我不使

  • 问题内容: 我需要在cfml页面中使用自己的java类。 文档中的此项听起来不错,但没有说明我必须创建哪些文件。 我试图在网站根目录下创建一个页面。然后将+ 放在同一路径中。但这会导致错误“找不到类”! 你能帮我么? 问题答案: 同一路径中的TestClass.java + TestClass.class。 您不能仅将文件放置在任何地方。CF服务器启动时, 仅 检查类/ jar的特定位置。这些位置

  • 我有一个实现REST API的spring boot应用程序。我有一个POSTendpoint,它通过接收一个对象,这个对象有几个字段,其中一些字段的类型为。我面临的问题是,当我接收到一个包含字母字符串作为long类型字段值的无效请求有效负载时,应用程序返回一个带有空有效负载的HTTP 400响应,但我希望能够自定义该响应(例如通过)并提供一些错误描述。然而,直到现在我都没能做到。 请求有效负载对

  • 我已经开发了一个Java web应用程序,我想实现SAML。我认为这些是实现SAML的正确步骤。 服务提供商(SP,在本例中是我的应用程序)向IdP发送SAML身份验证请求 然后,IdP对其进行验证,创建SAML响应断言,并将其与证书一起签名,然后发送回SP。 然后,SP使用密钥库中证书的公钥对其进行验证,并在此基础上进一步进行 我有一个示例代码,可以创建SAML请求 我可以对其进行编码并发送给I

  • 我正在尝试从JavaScript应用程序向另一个应用程序中的endpoint进行API调用。 当我调用endpoint时,我得到了状态代码和消息,但我无法以任何方式访问响应体。我已经尝试了不同的方法来获取数据,但似乎没有一种方法对我有效。 在方法“someAction”中,我想使用来自API调用的响应/结果中的数据。我在代码中添加了单个日志行打印的输出。 如何在定义“result.status/m