一篇文章让你搞懂如何通过Nginx来解决跨域问题

Nginx跨域实现

  首先大家要搞清楚什么是跨域,为什么会有跨域情况的出现。哪些情况属于跨域?

跨域:由于浏览器的同源策略,即属于不同域的页面之间不能相互访问各自的页面内容
:同源策略,单说来就是同协议,同域名,同端口

URL 说明 是否允许通信
//www.a.com/a.js
//www.a.com/b.js 同一域名下 允许
//www.a.com/lab/a.js
//www.a.com/script/b.js 同一域名下不同文件夹 允许
//www.a.com:8000/a.js
//www.a.com/b.js 同一域名,不同端口 不允许
//www.a.com/a.js
//www.a.com/b.js 同一域名,不同协议 不允许
//www.a.com/a.js
//70.32.92.74/b.js 域名和域名对应ip 不允许
//www.a.com/a.js
//script.a.com/b.js 主域相同,子域不同 不允许
//www.a.com/a.js
//a.com/b.js 同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
//www.cnblogs.com/a.js
//www.a.com/b.js 不同域名 不允许

跨域场景

  出于安全考虑(比如csrf攻击),浏览器一般会禁止进行跨域访问,但是因为有时有相应需求,需要允许跨域访问,这时,我们就需要将跨域访问限制打开。
  启动一个web服务,端口是8081
在这里插入图片描述
  然后再开启一个web服务/前端服务都可以。端口是8082,然后再8082的服务中通过ajax来访问8081的服务,这就不满足同源策略,就会出现跨域问题

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<h2>Hello World!</h2>
<script type="text/javascript">
    function fun1(){
        var request = new XMLHttpRequest();
        request.open("GET","//localhost:8081/user/query")
        request.send();
        request.onreadystatechange = function(){
            if(request.status==200 && request.readyState == 4){
                console.log("响应的结果" + request.responseText)
            }
        }
    }
</script>
</body>
    <input type="button" value="跨域调用" onclick="fun1()">
</html>

在这里插入图片描述

跨域问题的解决方案

  解决跨域问题的方式也有多种。

1、前后端结合(JsonP)

  虽然jsonp也可以实现跨域,但是因为jsonp不支持post请求,应用场景受到很大限制,所以这里不对jsonp作介绍。

2、纯后端方式一(CORS方式)

  CORS 是w3c标准的方式,通过在web服务器端设置:响应头Access-Cntrol-Alow-Origin 来指定哪些域可以访问本域的数据,ie8&9(XDomainRequest),10+,chrom4,firefox3.5,safair4,opera12支持这种方式。

  服务器代理,同源策略只存在浏览器端,通过服务器转发请求可以达到跨域请求的目的,劣势:增加服务器的负担,且访问速度慢。

在这里插入图片描述

3.纯后端方式二(Nginx代理方式)【建议这种方式】

  首先配置Nginx的反向代理方式
在这里插入图片描述

代理访问正常
在这里插入图片描述

8082的服务访问Nginx,出现了跨域问题

在这里插入图片描述

Nginx配置跨域解决

location / {  
    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;
}
proxy_pass //192.168.12.1:8081;
} 

解决了跨域问题
在这里插入图片描述

参数说明

Access-Control-Allow-Origin

  服务器默认是不被允许跨域的。给Nginx服务器配置Access-Control-Allow-Origin *后,表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求。

Access-Control-Allow-Headers

  是为了防止出现以下错误:

Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

  这个错误表示当前请求Content-Type的值不被支持。其实是我们发起了”application/json”的类型请求导致的。这里涉及到一个概念:预检请求(preflight request),请看下面”预检请求”的介绍。

Access-Control-Allow-Methods

  是为了防止出现以下错误:

Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

给OPTIONS 添加 204的返回

  是为了处理在发送POST请求时Nginx依然拒绝访问的错误,发送”预检请求”时,需要用到方法 OPTIONS ,所以服务器需要允许该方法。

预检请求(preflight request)

  跨域资源共享(CORS)标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。
  其实Content-Type字段的类型为application/json的请求就是上面所说的搭配某些 MIME 类型的 POST 请求,CORS规定,Content-Type不属于以下MIME类型的,都属于预检请求
  所以 application/json的请求 会在正式通信之前,增加一次”预检”请求,这次”预检”请求会带上头部信息 Access-Control-Request-Headers: Content-Type:

Tags: