前后端分离项目,跨域如何实现

一、前后端分离如何实现跨域?

前端:域名:localhost:8080

后端:域名:localhost:9000

前端单独部署,后端也单独部署

浏览器访问localhost:8080/test/one,/test/one内部逻辑会通过ajax访问对应得后端接口,localhost:9000/test/oneApi 这里就会发生跨域,返回结果就是403 Forbidden。

403 Forbidden 是HTTP协议中的一个状态码(Status Code),意味着后端服务虽然成功解析了请求,但前端却没有访问该资源的权限。
 

二、解决跨域方案

1)CORS分类


浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)
1.简单请求
只要同时满足以下两大条件,就属于简单请求

1.请求方法是以下三种方法之一:
HEAD
GET
POST
2.HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
2.非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT、DELETE或OPTIONS,或者Content-Type字段的类型是application/json。

非简单请求在正式通信之前,会增加一次 HTTP 查询请求,称为“预检”请求。预检请求通过后,才会返回正常的响应内容。

2)跨域处理方式


为什么要讲简单请求和非简单请求呢?因为浏览器对对这两种请求的处理,是不一样的。
1.简单请求
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
处理如下:

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
在nginx上经以上配置,一般能够解决简单请求的跨域处理。
CORS请求默认不发送Cookie和HTTP认证信息。但是如果要把Cookie发到服务器,要服务器同意,指定Access-Control-Allow-Credentials字段。

add_header 'Access-Control-Allow-Credentials' 'true';
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。


2.非简单请求

(1)非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight),预捡的请求方法是OPTIONS。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。


因此我们可以在浏览器的开发者工具中查看头信息,若头信息中有OPTIONS方法,说明此次CORS请求是非简单请求,需要在nginx中添加头:

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
此时虽然我们已经添加了所有的Methods方法,但是预检请求仍不会通过,因此此时nginx对OPTIONS方法返回"405 Method Not Allowed”或者403。我们需要在nginx对OPTIONS方法进行处理,如下:

if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
    add_header 'Access-Control-Allow-Headers' 'Content-Type';
    return 200;
}

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
#在location处添加以下内容
if ($request_method = 'OPTIONS') {
    return 200;
}
我们在nginx上将OPTIONS方法返回200,而不是405或403。

(2)服务器经过以上设置通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。

Nginx通过CORS,实现跨域
Nginx标准配置

server {
    ... ...
 
        # #设置跨域配置 Start
        set $cors_origin "";
        if ($http_origin ~* "^http://localhost:9000$"){
                set $cors_origin $http_origin;
        }

        if ($http_origin ~* "^http://localhost:9002$"){
                set $cors_origin $http_origin;
        }
 
        add_header Access-Control-Allow-Origin $cors_origin always; 
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS always;
        add_header Access-Control-Allow-Credentials true always;
        add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,x-auth-token always;
        add_header Access-Control-Max-Age 1728000 always;
 
        # 预检请求处理
        if ($request_method = OPTIONS) {
                return 204;
        }
        # #设置跨域配置 End
 
    ... ...
}
1.设置Origin:表示服务器可以接受的请求

add_header Access-Control-Allow-Origin http://localhost:9000
表示 http://localhost:9000 可以请求数据。这个可以设置为*星号代表任意跨源请求都支持,但不建议这样设置;因为设置为*星号将不在支持发送Cookie

2.设置多域名配置

        set $cors_origin "";
        if ($http_origin ~* "^http://localhost:9000$"){
                set $cors_origin $http_origin;
        }
        if ($http_origin ~* "^http://localhost:9002$"){
                set $cors_origin $http_origin;
        }
这个写法主要是为了支持多域名设置,通过对请求origin的判断是否与指定跨域源一致,然后在进行header的设置;

3.设置跨域支持的请求类型

add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS always;
4.设置跨域请求是否允许发送Cookie,true:支持,false:不支持

add_header Access-Control-Allow-Credentials true always;
5.设置跨域请求允许的Header头信息字段,以逗号分隔的字符串

add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,x-auth-token always;
注:需要特别注意,凡是API中约定了自定义Header,都需要在这里增加,否则不可以跨域请求。

6.本次预检请求的有效期,单位为秒,在允许缓存该条请求回应1728000秒内,无需在发出一条预检请求。

add_header Access-Control-Max-Age 1728000 always;
7.always 参数的定义

... ... always
Nginx 规则 add_header默认只会加入到指定response code的请求中;

见官网介绍:

Syntax: add_header name value [always];
Default:    —
Context:    http, server, location, if in location
 
 
Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0). The value can contain variables.
指定了 always则无论什么请求都添加header:

If the always parameter is specified (1.7.5), the header field will be added regardless of the response code.


8.预检请求处理

        if ($request_method = OPTIONS) {
                return 204;
        }
CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight);浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的,因此我们需要在Nginx配置中,针对预检请求进行处理,直接返回204 & Response Header,表示服务器支持允许跨源的访问。
 

3)前端改造

const requestService = axios.create({
  baseURL: 'http://localhost:9000', // api 的 base_url
  timeout: 60000 // request timeout
});//构建得ajax完整请求全部为后端域名开头

requestService.defaults.withCredentials = true;

CORS请求默认不发送Cookie和HTTP认证信息,如果需要支持,除了服务端增加设置,AJAX请求中打开withCredentials属性

        

  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值