Nginx处理CORS(跨站资源共享)

我在部署 NGINX反向代理https 启用了 docs.cloud-atlas.io 构建 "云图 -- 云计算图志: 探索" 自建网站。但是发现一个问题,原本 utterances 构建的 Sphinx文档评论系统 无法展示了。

这个问题是我刚切换到 FreeBSD XFCE桌面 作为工作平台时发现的,使用浏览器 Firefox 存在这个现象,而之前在 macOS 平台使用Safari就没有这个问题。看来Firefox有什么特别之处,所以开启 Firefox 的developer tools 观察页面加载情况,就发现原来 https://uteranc.es/client.js 无法加载,提示 CORS error

简单来说,处于网站安全,一个HTTPS加密网站的所有页面应该是(最好)从同一个域名提供,也就是客户端浏览器仅信任自己访问的网站。但是,如果页面中嵌入了其他网站资源,那么从安全严格来讲,客户端有一定理由怀疑存在安全隐患。所以,如果浏览器设置较高安全等级,是会拒绝这种跨域内容的。

解决的方法也比较简单,就是在NGINX发送给客户端ORIGN请求的响应内容的头部插入 Access-Control-Allow-Origin 字段,表示网站信任和接受那哪些网站提供的资源。o

对于我这里的实践 NGINX反向代理https ,实际上只要在后端NGINX(也就是反响代理所指向的真正提供内容的后端NGINX服务器上)配置:

NGINX添加允许 https://utteranc.es CORS
server {
    include /etc/nginx/includes/server.conf;

    server_name cloud-atlas.io www.cloud-atlas.io;
    root /var/web/cloud-atlas.io/www;
}

server {
    include /etc/nginx/includes/server.conf;

    server_name docs.cloud-atlas.io;
    root /var/web/cloud-atlas.io/docs;

    location /discovery {
        add_header 'Access-Control-Allow-Origin' 'https://utteranc.es';
        alias /var/web/cloud-atlas.io/docs.discovery;
    }
}

不过,还是存在一点问题,如果访问用户登陆过github,那么 utteranc.es 还会调用 api.github.com ,所以实际上我们需要设置多个domain的CORS。为了能够方便配置,采用 Nginx配置文件的include 包含一个domain的map来解决:结合两个配置文件

  • /etc/nginx/conf.d/cloud-atlas.io.conf :

通过 Nginx配置文件的include 引入map来添加 CORS
include /etc/nginx/includes/origin_map.conf;

server {
    include /etc/nginx/includes/server.conf;

    server_name cloud-atlas.io www.cloud-atlas.io;
    root /var/web/cloud-atlas.io/www;
}

server {
    include /etc/nginx/includes/server.conf;

    server_name docs.cloud-atlas.io;
    root /var/web/cloud-atlas.io/docs;

    location /discovery {
        add_header 'Access-Control-Allow-Origin' '$cors' always;
        alias /var/web/cloud-atlas.io/docs.discovery;
    }
}
  • /etc/nginx/includes/origin_map.conf :

origin_map.conf 配置了一个NGINX map
#Map the needed frontend URLS to the cors variable
map "$http_origin" $cors {
  default '';
  "~^https?://api.github.com?$" "$http_origin";
  "~^https?://utteranc.es?$" "$http_origin";
}

全面放开nginx的CORS配置

  • 使用以下nginx配置可以放开CORS:

Nginx 放开 CORS
#
# Wide-open CORS config for nginx
#
location / {
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        #
        # Om nom nom cookies
        #
        add_header 'Access-Control-Allow-Credentials' 'true';
        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,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';

        #
        # 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' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
}

参考