我在VPS上的设置如下:
- golang后端,在www.example.com上的Docker容器中公开REST API127.0.0.1:6060
- 苗条的前端,使用节点适配器构建,在Node.js进程中运行,网址为127.0.0.1:3000
- nginx作为反向代理,使用certbot for https
我使用了一个域名(我们称之为https://example.com
),它通过DNS A记录重定向到我的VPS IP。到目前为止一切顺利,前端运行在我的域上。
我的nginx设置基本如下:
server {
server_name example.com www.example.com;
location / {
proxy_pass http://localhost:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
加上certbot的东西。
我使用js fetch()请求来调用我的golang REST API。
在我的后端http服务器中,我设置了以下标题来处理CORS:
headers.Add("Access-Control-Allow-Credentials", "true")
headers.Add("Access-Control-Allow-Origin", "https:example.com")
headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
if req.Method != http.MethodOptions {
next.ServeHTTP(rw, req)
return
}
// process an HTTP OPTIONS preflight request
headers.Add("Access-Control-Allow-Headers", "content-type, allow-credentials")
我还使用autocert包的管理器来处理https,设置如下所示:
m := &autocert.Manager{
Cache: autocert.DirCache("secret-dir"),
Prompt: autocert.AcceptTOS,
Email: "example@example.org",
HostPolicy: autocert.HostWhitelist("example.com", "www.example.com"),
}
server := &http.Server{
// Addr: ":6060",
Addr: ":https",
TLSConfig: m.TLSConfig(),
// Set timeouts to avoid Slowloris attacks.
WriteTimeout: time.Second * 15,
ReadTimeout: time.Second * 15,
IdleTimeout: time.Second * 60,
Handler: routerWithCORS,
}
我的GET(等)请求调用https://127.0.0.1:6060/api/v1/whatever
,调用的来源是https://example.com
,在浏览器的网络选项卡中,我得到
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://127.0.0.1:6060/api/v1/me. (Reason: CORS request did not succeed). Status code: (null).
我还应用了这个广泛开放的nginx设置来启用nginx中的CORS,但没有成功:
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}
}
我以为我的golang后端不需要https,因为请求来自127.0.0.1VPS上的www.example.com,并且在同一个VPS上调用127.0.0.1:6060,但是查看网络选项卡,调用的来源是https://example.com。所以我想这是主要问题。我不能从https来源调用http资源。但是即使在https中运行后端也不起作用。
我希望能有一个不那么复杂的解决办法来解决这个问题,希望能帮助我找到正确的方向。
1条答案
按热度按时间dluptydi1#
最多在一个位置配置CORS
通过在多个地点配置CORS,
您会引发问题。CORS应最多在一个位置进行配置,只要配置更容易,配置更改更容易得到审查。
支持在应用程序级别配置CORS
那么您应该在哪里配置CORS呢?在NGINX这样的反向代理中配置CORS可能会很有挑战性,因为您无法获得Go这样的编程语言的全部表达能力。这就是为什么我倾向于在应用程序级别配置CORS。
依靠成熟的CORS中间件
通过手动设置响应标头来配置CORS很有吸引力,但容易出错,尤其是在您不熟悉该协议的情况下。
https:example.com
不是有效的Web origin,因此第一条语句不可能按预期工作;你是说https://example.com
。OPTIONS
列为允许的方法。Access-Control-Allow-Methods
在响应非预检请求时没有位置。OPTIONS
请求都是印前检查请求。所有这些困难应该足以让您相信,最好还是依赖一个经过验证的CORS中间件库,它可以将这些复杂性中的一部分从您的身上抽象出来。
使用jub 0 bs/fcors的解决方案
我最近发布了jub0bs/fcors,这是一个CORS中间件库,其设计易于使用,更重要的是,* 难以误用 *。
(For信息,名为
cors
的结果具有类型func(http.Handler) http.Handler
。)调整此示例以满足您的需要,并删除NGINX配置中与CORS相关的所有内容。