Cross Origin Resource Share (CORS)

CORS是一个跨域资源共享方案,为了解决跨域问题,通过增加一系列请求头和响应头,规范安全地进行跨站数据传输

请求头主要包括

请求头解释
Origin Origin头在跨域请求或预先请求中,标明发起跨域请求的源域名。
Access-Control-Request-Method Access-Control-Request-Method头用于表明跨域请求使用的实际HTTP方法
Access-Control-Request-Headers Access-Control-Request-Headers用于在预先请求时,告知服务器要发起的跨域请求中会携带的请求头信息
with-credentials 跨域请求携带cookie

响应头主要包括

响应头解释
Access-Control-Allow-Origin Access-Control-Allow-Origin头中携带了服务器端验证后的允许的跨域请求域名,可以是一个具体的域名或是一个*(表示任意域名)。
Access-Control-Expose-Headers Access-Control-Expose-Headers头用于允许返回给跨域请求的响应头列表,在列表中的响应头的内容,才可以被浏览器访问。
Access-Control-Max-Age Access-Control-Max-Age用于告知浏览器可以将预先检查请求返回结果缓存的时间,在缓存有效期内,浏览器会使用缓存的预先检查结果判断是否发送跨域请求。
Access-Control-Allow-Methods Access-Control-Allow-Methods用于告知浏览器可以在实际发送跨域请求时,可以支持的请求方法,可以是一个具体的方法列表或是一个*(表示任意方法)。

如何使用

  • 客户端只需按规范设置请求头。
  • 服务端按规范识别并返回对应响应头,或者安装相应插件,修改相应框架配置文件等。具体视服务端所用的语言和框架而定。

SpringBoot 设置CORS例子

一个spring boot项目中关于CORS配置的一段代码

 
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String temp = request.getHeader("Origin");
        httpServletResponse.setHeader("Access-Control-Allow-Origin", temp);
        // 允许的访问方法
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
//         Access-Control-Max-Age 用于 CORS 相关配置的缓存
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
        httpServletResponse.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept,token");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");

JSONP 跨域

jsonp的原理就是借助HTML中的<script>标签可以跨域引入资源。所以动态创建一个<srcipt>标签,src为目的接口 + get数据包 + 处理数据的函数名。后台收到GET请求后解析并返回函数名(数据)给前端,前端<script>标签动态执行处理函数
观察下面代码

  • 前端代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <script>
        var script = document.createElement('script');
        script.type = 'text/javascript';
    
        // 传参并指定回调执行函数为getData
        script.src = 'http://localhost:8080/users?username=xbc&callback=handleData';
        document.body.appendChild(script);
        // 回调执行函数
        function handleData(res) {
            data = JSON.stringify(res)
            console.log(data);
        }
    </script>
    </body>
    </html>
  • 后端代码(nodejs)

     
    var querystring = require('querystring');
    var http = require('http');
    var server = http.createServer();
    
    server.on('request', function(req, res) {
        var params = querystring.parse(req.url.split('?')[1]);
        var fn = params.callback;
    
        // jsonp返回设置
        res.writeHead(200, { 'Content-Type': 'text/javascript' });
        var data = {
            user: 'xbc',
            password: '123456'
        }
        res.write(fn + '(' + JSON.stringify(data) + ')');
    
        res.end();
    });
    
    server.listen('8080');
    console.log('Server is running at port 8080...');

在该例子中,前台收到的res是这样的
图片描述

 

前端页面是这样的
图片描述

注意:JSONP既是利用了<srcipt>,那么就只能支持GET请求。其他请求无法实现