ngixn笔记(1) 前后端跨域设置

最近公司项目需要我调用别的部门开发的接口,由于部门之间服务器独立,必然涉及到了跨域问题。这篇文章记录了我配置的nginx,前后端允许跨域。

跨域的产生

首先明确跨域的产生是由于浏览器通源策略,限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

问题描述

发了请求之后迟迟没有收到回复,打开控制台一看,请求404了,再仔细找原因之后发现,我原来发送的post请求变成了option请求。
chrome跨域

chrome认为前端没有添加头部信息,所以不允许前端页面发出请求。
chrome跨域

后端允许跨域(开发环境)

服务器默认是不被允许跨域的。给Nginx服务器配置Access-Control-Allow-Origin *后,表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求。 Access-Control-Allow-Methods 是为了防止出现Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. Access-Control-Allow-Headers是为了防止出现当前请求Content-Type的值不被支持,当发起了application/json的类型请求时添加这个头可以解决。
服务器nginx添加以下配置:

1
2
3
4
5
6
7
8
9
location /myurl/ {  
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

if ($request_method = 'OPTIONS') {
return 204;
}
}

预检请求

对那些可能对服务器数据产生副作用的HTTP请求方法(特别是GET以外的HTTP请求,或者搭配某些MIME类型的POST请求),浏览器必须首先使用 OPTIONS方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的HTTP请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

Content-Type不属于以下MIME类型的,都属于预检请求:

1
2
3
application/x-www-form-urlencoded
multipart/form-data
text/plain

OPTIONS先行验证是否允许跨域,若不允许,就不会进行下一个POST请求,所以之前会出现请求404的情况。

后端允许跨域(生产环境)

此时处于生产环境,允许所有请求不太安全,所以可以由后端自定义请求的格式,当格式符合条件时,才添加跨域头。
后端接口一般带有统一前缀,这里设置所有带有api的请求都可以绕过跨域限制。
nginx.conf中修改结果如下:

1
2
3
4
location /api {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
}

前端允许跨域(生产环境)

由于这个项目涉及到了不同部门的接口,某个前辈的接口并没有按照规定来写,所以这里前端需要自己修改一下地址格式。
例如:原来的请求地址为http://abc.com/origin,现在设计一个新的请求地址http://abc.com/myapi/origin
修改nginx配置如下:

1
2
3
4
5
6
7
8
9
location /myurl/ {
root /home/guoningyan/myproject/;
index index.html;
try_files $uri $uri/ @router;
}

location /myapi/origin {
proxy_pass http://abc.com/origin;
}

意思为当发送的请求以/myapi/origin为后缀时,自动代理到原请求地址http://abc.com/origin
有一点要注意的是,在nginx中配置proxy_pass代理转发时,如果在proxy_pass后面的url加/,表示绝对根路径;如果没有/,表示相对路径。