设置HTTP标头

时间:2012-10-10 23:39:13

标签: http go cors http-headers

我正在尝试在Go网络服务器中设置标头。我正在使用gorilla/muxnet/http个包。

我想将Access-Control-Allow-Origin: *设置为允许跨域AJAX。

这是我的Go代码:

func saveHandler(w http.ResponseWriter, r *http.Request) {
// do some stuff with the request data
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/save", saveHandler)
    http.Handle("/", r)
    http.ListenAndServe(":"+port, nil)
}

net/http包中包含描述发送http请求标头的文档,就像它是客户端一样 - 我不确定如何设置响应标头?

8 个答案:

答案 0 :(得分:204)

没关系,我弄明白了 - 我在Set()上使用Header()方法(doh!)

我的处理程序现在看起来像这样:

func saveHandler(w http.ResponseWriter, r *http.Request) {
    // allow cross domain AJAX requests
    w.Header().Set("Access-Control-Allow-Origin", "*")
}

也许这会帮助某些人像咖啡因一样被剥夺自己的某些时间:)

答案 1 :(得分:98)

以上所有答案都是错误的,因为它们无法处理OPTIONS预检请求,解决方案是覆盖多路复用路由器的界面。见AngularJS $http get request failed with custom header (alllowed in CORS)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/save", saveHandler)
    http.Handle("/", &MyServer{r})
    http.ListenAndServe(":8080", nil);

}

type MyServer struct {
    r *mux.Router
}

func (s *MyServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    if origin := req.Header.Get("Origin"); origin != "" {
        rw.Header().Set("Access-Control-Allow-Origin", origin)
        rw.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
        rw.Header().Set("Access-Control-Allow-Headers",
            "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
    }
    // Stop here if its Preflighted OPTIONS request
    if req.Method == "OPTIONS" {
        return
    }
    // Lets Gorilla work
    s.r.ServeHTTP(rw, req)
}

答案 2 :(得分:22)

对于Origin,请不要使用'*',直到您真正需要完全公开的行为 正如Wikipedia says

  

“”*的值很特殊,因为它不允许请求提供凭据,   意味着HTTP身份验证,客户端SSL证书,也不允许cookie   被发送。“

这意味着,您会遇到很多错误,尤其是在Chrome尝试实施简单身份验证时。

这是一个更正的包装器:

// Code has not been tested.
func addDefaultHeaders(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if origin := r.Header.Get("Origin"); origin != "" {
            w.Header().Set("Access-Control-Allow-Origin", origin)
        }
        w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
        w.Header().Set("Access-Control-Allow-Credentials", "true")
        fn(w, r)
    }
}

不要忘记将所有这些标题回复到预检OPTIONS请求。

答案 3 :(得分:13)

设置合适的golang中间件,以便在任何端点上重用。

助手类型和功能

type Adapter func(http.Handler) http.Handler
// Adapt h with all specified adapters.
func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
    for _, adapter := range adapters {
        h = adapter(h)
    }
    return h
}

实际中间件

func EnableCORS() Adapter {
    return func(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

            if origin := r.Header.Get("Origin"); origin != "" {
                w.Header().Set("Access-Control-Allow-Origin", origin)
                w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
                w.Header().Set("Access-Control-Allow-Headers",
                    "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
            }
            // Stop here if its Preflighted OPTIONS request
            if r.Method == "OPTIONS" {
                return
            }
            h.ServeHTTP(w, r)
        })
    }
}

端点

REMEBER!中间件以相反的顺序应用(ExpectGET()首先触发)

mux.Handle("/watcher/{action}/{device}",Adapt(api.SerialHandler(mux),
    api.EnableCORS(),
    api.ExpectGET(),
))

答案 4 :(得分:12)

我为这种情况创建了包装器:

func addDefaultHeaders(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        fn(w, r)
    }
}

答案 5 :(得分:10)

如果您不想覆盖路由器(如果您没有以支持此功能的方式配置您的应用,或者想要在路由上配置CORS路线基础),添加一个OPTIONS处理程序来处理飞行前请求。

也就是说,对于Gorilla Mux,您的路线看起来像:

accounts := router.Path("/accounts").Subrouter()
accounts.Methods("POST").Handler(AccountsCreate)
accounts.Methods("OPTIONS").Handler(AccountsCreatePreFlight)

请注意,除了我们的POST处理程序之外,我们正在定义特定的OPTIONS方法处理程序

然后要实际处理OPTIONS预检方法,您可以像这样定义AccountsCreatePreFlight:

// Check the origin is valid.
origin := r.Header.Get("Origin")
validOrigin, err := validateOrigin(origin)
if err != nil {
    return err
}

// If it is, allow CORS.
if validOrigin {
    w.Header().Set("Access-Control-Allow-Origin", origin)
    w.Header().Set("Access-Control-Allow-Methods", "POST")
    w.Header().Set("Access-Control-Allow-Headers",
        "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}

真正让我点击这一切(除了实际理解CORS如何工作之外)是预检请求的HTTP方法与实际请求的HTTP方法不同。要启动CORS,浏览器使用HTTP方法OPTIONS发送预检请求,您必须在路由器中明确处理,然后,如果它收到适当的响应"Access-Control-Allow-Origin": origin(或" *" )从您的应用程序,它启动实际请求。

我也相信你只能做" *"对于标准类型的请求(即:GET),但对于其他人,您必须像我上面那样明确设置原点。

答案 6 :(得分:1)

我遇到与上述相同的问题,上面给出的解决方案是正确的,我的设置如下 1)客户的Angularjs 2)GO服务器的Beego框架

请遵循以下几点 1)必须仅在GO服务器上启用CORS设置 2)除了

之外,不要在angularJS中添加任何类型的标题
.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }])

在GO服务器中,在请求开始处理之前添加CORS设置,以便预检请求收到200 OK,之后OPTIONS方法将转换为GET,POST,PUT或者您的请求类型。

答案 7 :(得分:-7)

我知道这是一个不同的答案,但这不是一个关注Web服务器的问题吗?例如, nginx 可以提供帮助。

  

ngx_http_headers_module 模块允许将“Expires”和“Cache-Control”标头字段以及任意字段添加到响应标头

...

location ~ ^<REGXP MATCHING CORS ROUTES> {
    add_header Access-Control-Allow-Methods POST
    ...
}
...

在生产服务中添加 nginx 似乎是明智之举。它为授权,记录和修改请求提供了更多功能。此外,它还能够控制谁有权访问您的服务,而不仅仅是,但可以为应用中的特定位置指定不同的行为,如上所示。

我可以继续讨论为什么要使用go api使用网络服务器,但我认为这是另一个讨论的主题。