关于跨域,你须要知道的

前言:跨域对于大多数开发人员并不陌生,可是当咱们遇到跨域的时候,大部分前端开发者都会说出一种解决方案:让服务端设置一下参数就好了。那为何服务端设置了这些参数就能解决跨域问题呢?除了服务端解决,还有没有其余的解决方案呢?本文会具体分析一下产生跨域的缘由以及其余的解决跨域的方案。javascript

1、为何会跨域

一、什么是跨域
假若有一个页面A(url:https://www.a.com),页面中有一个接口请求:https://www.b.com/getData;当咱们在浏览器中发送这个请求的时候,浏览器就会报错,错误信息大概以下:前端

Access to XMLHttpRequest at 'https://www.b.com/' from origin 'https://www.a.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.java

看到这个错误你们就知道了产生了跨域的问题。
二、跨域的缘由
知道了什么是跨域,那为何会产生跨域的问题呢?
浏览器为了保护用户的信息安全提出了同源策略(注:这里须要特别注意一下是在浏览器中才会有同源策略的限制):node

  • 协议相同
  • 域名相同
  • 端口相同

只有同时知足以上三个条件,咱们就说两个url是同源的;因此,非同源之间就会产生跨域的问题。那既然知道了跨域产生的缘由,接下来咱们看一下几种经常使用的解决跨域的方案。固然,也有其余的方案,这里就很少说了,你们能够自行查询一下。web

2、解决跨域的几种方案

一、JSONP
jsonp全称是json with padding,这是一种比较"古老"的解决跨域的方案,在那个年代,对于一些简单的get请求,咱们能够经过这种方式解决;可是其余的一些复杂的请求(好比post),就须要用一些现代的方法解决了,那为何jsonp不能发post请求呢?这要看一下jsonp解决跨域的原理:json

虽然浏览器有同源策略的限制,可是script标签却不受同源策略的限制,也就是经过script咱们能够向不一样的源发出请求。跨域

因为script经过src发出的是get请求,因此jsonp的方式不不能解决post请求的跨域的。浏览器

// 客户端代码
function doJSONPRequestClickHandler() {
    let script = document.createElement('script');
    script.src = 'http://www.b.com/jsonp?callback=handleCallback';
    document.body.appendChild(script);
}
// 回调
let handleCallback = function(res) {
    console.log(res);
}
复制代码

jsonp最关键的点就是http://www.b.com/jsonp?callback=handleCallback后面的callback参数,服务端接收到请求以后要处理这个参数:安全

// 服务端用nodejs
app.get('/jsonp', (req, res) => {
    let cb = req.query.callback;
    res.send(cb + '("jsonp跨域成功")');
});
复制代码

当浏览器接收到服务端的响应也就是成功加载了js,就会当即执行handleCallback('jsonp跨域成功');
以上就是jsonp跨域的原理。
二、代理
使用代理的方式解决跨域的原理也很好理解:同源策略只是在浏览器中限制的,离开了浏览器环境是不受同源策略的限制的,因此经过代理的方式,将咱们的接口请求先发到同源的代理,而后再经过代理服务器转发到目的服务器。
下面是经过nodejs中间件代理的方式解决跨域:服务器

const http = require('http');
const httpProxy = require('http-proxy');

const proxy = httpProxy.createProxyServer();

http.createServer((request, response) => {
    proxy.web(request, response, {
        target: 'https://www.b.com',
        changeOrigin: true,
    });
    proxy.on('error', err => {
        console.log(err);
    });
}).listen(8081);
复制代码

三、CORS
文章刚开始讲到的“让服务端设置一下参数”就是经过CORS的方式解决跨域的,那么什么是CORS呢?
CORS就是跨源资源共享,虽然浏览器有同源策略的限制,可是浏览器给咱们开了一个“后门”,浏览器是容许发送跨域请求的,可是须要服务端配合在响应头中设置一些特定的response header:

  • Access-Control-Allow-Origin: | *
  • Access-Control-Allow-Methods: [, ]*
  • Access-Control-Allow-Headers: [, ]*
  • Access-Control-Allow-Credentials: true
  • Access-Control-Allow-Origin

这个值是告诉客户端容许的源是哪些,能够设置为特定的一个源或者*,当设置为的时候容许全部的源跨域请求,这个设置为的时候要很是当心;

  • Access-Control-Allow-Methods

它告诉客户端容许跨域请求的方法是什么,好比GET,POST,PUT等,能够设置多个

  • Access-Control-Allow-Headers

若是请求头中有一些自定义的请求头,就须要设置这个属性了,能够设置多个

  • Access-Control-Allow-Credentials

当咱们的请求中须要带一些cookie信息的时候,须要设置它的值为true,须要注意一点,若是要使用这个属性,那么 Access-Control-Allow-Origin的值不能设置为*。
CORS的设置以下:

app.post('/saveData', (req,res) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'POST');
    res.header('Access-Control-Allow-Headers', 'custom');
    console.log(req.body.name);
    res.send('接到了数据' + req.body.name);
});
复制代码

三、总结

以上介绍了什么是跨域,以及产生跨域的缘由;产生跨域时的几种解决方案:jsonp、代理、cors...;经过以上的介绍,以后咱们再遇到跨域的问题的时候再也不只会说“让服务端设置一下参数就好了”,可以明白为何要服务端设置。 对于其余的一些解决跨域的方案,本文中没有说起,你们感兴趣能够本身研究一下,好比经过websocket、iframe等方式。