8

前言

我们有很多种方式解决跨域请求
本篇为大家讲解使用CORS解决跨域

CORS又称跨域资源共享
它需要浏览器和服务器的同时支持
在开发过程中,浏览器并不会有过多的变化
服务器是关键,只有服务器实现了CORS接口,才可以进行跨域请求

CORS对于浏览器发过来的AJAX跨域请求分为两种:
简单请求和非简单请求

简单请求

所谓简单请求就是HEAD,GET,POST三种请求方式
浏览器会在在header信息里面多加一个字段:
key:origin
value:协议+域名+端口(如https://localhost:8080)

服务器根据对象里的origin值来决定是否同意这次请求

如果请求通过
请求通过后,服务器会在header里多增加几个字段:

Access-Control-Allow-Origin: https://localhost:8080
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Token

解释:
1.Credentials是否允许包含cookie,如果返回了true,那么浏览器发送请求体的时候要添加:

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

如此这般,才能向服务器发送cookie

2.Access-Control-Expose-Headers是多返回的字段名,根据实际需求改变

如果请求失败
说明之前发送Origin的value不在许可范围内
服务器会返回一个正常的HTTP回应
浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段
从而抛出一个无法跨域的异常(可能是200,所以无法识别)

非简单请求

简单请求的方法是Head,Get,Post
那么非简单请求的方法就是Put,Delete,或者Content-Type是application/json

非简单请求在发出CORS请求之前,会增加一次HTTP查询请求,也叫预检请求
预检请求成功了,浏览器才能发出XMLHttpRequest,否则报错

如果浏览器发现这是一个非简单请求
就会先发送一个预检请求:

OPTIONS /cors HTTP/1.1
Origin: http://localhost:8088
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: token

预测请求的方法名叫OPTIONS
Origin和简单请求一样
Access-Control-Request-Method是请求方法
Access-Control-Request-Headers是额外发送的头信息字段
(tip:预检请求一般缓存下来,以便不需要在每次请求都发送)

如果预检请求通过
我们来看下服务器发出的回应

HTTP/1.1 200 OK
Date: Nov, 01 Dec 2017 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://localhost:8088
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: token
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

如果预检请求失败
服务器会返回一个HTTP回应(没有CORS的头信息字段)
并在console打出not allowed by Access-Control-Allow-Origin异常

预检请求通过以后
浏览器发每次出的CORS请求就和简单请求一样
会有一个origin字段
服务器每次回应都会有Access-Control-Allow-Origin头信息字段

前后端代码实现

前端jQuery写法:

$.ajax({
    type: "POST",
    url: baseUrl + "/post",
    dataType: 'json',
    crossDomain: true,
    xhrFields: {
        withCredentials: true
    },
    data: {
        name: "name_from_frontend"
    },
    success: function (response) {
        console.log(response)// 返回的 json 数据
        $("#response").val(JSON.stringify(response));
    }
});

crossDomain: true是指开启跨域

后端mvc配置类:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**/*").allowedOrigins("*");
    }
}

这是spring4.2以上版本

如果是4.2以下的:

public class CrossDomainFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");// 如果提示 * 不行,请往下看
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        filterChain.doFilter(request, response);
    }
}

4.2以下还需加过滤器:

<filter>
    <filter-name>CrossDomainFilter</filter-name>
    <filter-class>com.javadoop.filters.CrossDomainFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CrossDomainFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

以上便是CORS请求的原理;
觉得还可以的请点个赞,赞不了也可以收藏下;
总之,谢谢阅读~


大叔一枝花
610 声望56 粉丝

Talk is cheap,show me the code


引用和评论

0 条评论