我正在尝试在Go网络服务器中设置标头。我正在使用gorilla/mux
和net/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请求标头的文档,就像它是客户端一样 - 我不确定如何设置响应标头?
答案 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)
})
}
}
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使用网络服务器,但我认为这是另一个讨论的主题。