Golang中使用gorilla/handlers包遇到的CORS问题如何解决

Golang中使用gorilla/handlers包遇到的CORS问题如何解决 我有以下CORS配置:

headersOk := handlers.AllowedHeaders([]string{"Authorization", "Content-Type", "Origin", "Accept", "Accept-Language", "Accept-Encoding", "Cache-Control", "Content-Length", "X-Requested-With"})
originsOk := handlers.AllowedOrigins([]string{"http://localhost:8080", "http://localhost:5000"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
log.Fatal(http.ListenAndServe(":"+port, handlers.CORS(handlers.AllowCredentials(), originsOk, headersOk, methodsOk)(router)))

对于上述CORS配置,当使用Content-Type: application/json时,来自JavaScript XMLHttpRequest的请求工作正常。但是,当请求的Content-Typemultipart/form-data; boundary=someboundary时,会抛出以下错误:

Access to XMLHttpRequest at ‘https://example.com/profile/edit’ from origin ‘http://localhost:5000’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

请帮忙解释为什么multipart/form-data请求会触发CORS拦截。


更多关于Golang中使用gorilla/handlers包遇到的CORS问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

您的CORS允许的域名中不包含 example.com

CORS中存在一个简单请求的判断。如果一个请求是简单请求,则不需要进行CORS预检,会直接使用CORS策略进行判断。

简单请求要求请求方法是 HEAD、GET、POST 中的一种;请求头仅包含 AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type,没有额外的自定义头;并且 Content-Type 的值是 application/x-www-form-urlencodedmultipart/form-datatext/plain 三者之一。

更多信息请自行搜索。

更多关于Golang中使用gorilla/handlers包遇到的CORS问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题在于multipart/form-data请求会触发浏览器发送预检请求(preflight request),而预检请求的Content-Type头部值会包含boundary参数。你的配置中只允许Content-Typeapplication/json,没有包含multipart/form-data

当浏览器发送multipart/form-data请求时,会先发送一个OPTIONS方法的预检请求,其Content-Type头部值为multipart/form-data; boundary=someboundary。由于这个值不在你配置的AllowedHeaders列表中,CORS中间件会拒绝该请求。

解决方案是修改AllowedHeaders配置,允许multipart/form-dataContent-Type头部:

headersOk := handlers.AllowedHeaders([]string{
    "Authorization",
    "Content-Type",
    "Origin",
    "Accept",
    "Accept-Language",
    "Accept-Encoding",
    "Cache-Control",
    "Content-Length",
    "X-Requested-With",
})

实际上,handlers.AllowedHeaders配置的是服务器允许客户端发送的头部列表,而不是Access-Control-Allow-Headers响应头部的值。对于Content-Type,你只需要在列表中包含Content-Type即可,不需要指定具体的MIME类型。

完整示例:

package main

import (
    "log"
    "net/http"
    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
)

func main() {
    router := mux.NewRouter()
    router.HandleFunc("/profile/edit", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.Write([]byte(`{"status":"ok"}`))
    })

    headersOk := handlers.AllowedHeaders([]string{
        "Authorization",
        "Content-Type", // 只需要包含Content-Type,不需要指定具体类型
        "Origin",
        "Accept",
        "Accept-Language",
        "Accept-Encoding",
        "Cache-Control",
        "Content-Length",
        "X-Requested-With",
    })
    
    originsOk := handlers.AllowedOrigins([]string{
        "http://localhost:8080",
        "http://localhost:5000",
    })
    
    methodsOk := handlers.AllowedMethods([]string{
        "GET", "HEAD", "POST", "PUT", "OPTIONS",
    })

    port := "8080"
    log.Fatal(http.ListenAndServe(":"+port, 
        handlers.CORS(
            handlers.AllowCredentials(),
            originsOk,
            headersOk,
            methodsOk,
        )(router),
    ))
}

这样配置后,浏览器发送的multipart/form-data; boundary=someboundary请求就能正常通过CORS检查了。

回到顶部