跨域是浏览器的行为,限制了浏览器中资源对资源的访问,和http协议没有关系
同源策略
协议/主机/端口号都相同被视为同一源。
同源策略限制了什么?
cookie,session,localStorage,indexDB无法读取
Dom对象不能获取
XML,fetch不能发送
如何解决跨域?
CORS
使用额外的http请求头来告诉浏览器,让运行在一个origin上的web应用准许被跨域访问。
当发生CORS跨域请求时,浏览器会发出一个Options的预检(Preflight)请求,preflight请求包含如下3个关键的头信息:
- Origin:请求源
- Access-Control-Request-Method:浏览器的CORS会用到的方法
- Access-Control-Request-Headers:浏览器的CORS请求会额外发送的头信息字段
服务端接收到preflight请求后检查上述请求头,确认是否允许跨域并作出响应,响应中包含3个关键的响应头:
- Access-Control-Allow-Origin: 允许的请求源
- Access-Control-Allow-Method: 允许使用的方法
- Access-Control-Allow-Headers:允许的头信息字段
nodejs做中间件
服务端向服务端发送请求是不会引起跨域的。
使用nodejs接收前端传来的接口数据,之后将数据做出处理后再返送给原接口,源接口收到请求后返回的数据再经由nodejs返回给前端。
如果前端和nodejs不是同源的,则需要处理两者的跨域
nginx反向代理
正向代理:
反向代理:
例如我们可以使用nginx监听请求,当请求为/api/xx时,将该请求转发到http://118.195.129.130:5678,从而避免跨域。
上述客户端地址可以为代理服务器本身也就是http://118.195.129.131:9999,或者是另外一个ip地址。
#nginx配置。
#例如当客户端请求为http://118.195.129.131:9999/api/getUser时,将该请求转发到http://118.195.129.130:5678/api/getUser
listen 9999;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
location /api/ {
proxy_pass http://118.195.129.130:5678;
}
vue,React在开发环境中处理跨域的方式也和上述方式一样,只不过代理服务器为本地服务器(localhost:8080)。
jsonp
css中一部分标签是允许跨域的,如img,iframe,link,script,JSONP(JSON with Padding)即通过在script标签的src属性里访问目标接口以及拼接callback函数。
缺点:只能解决get请求,对错误处理有限。callback函数需要后端额外处理。
//前端
01 <!DOCTYPE html>
02 <html lang='en'>
03
04 <head>
05 <meta charset='UTF-8'>
06 <title></title>
07 </head>
08
09 <body>
10 <button id="btn_id">JSONP跨域获取数据</button>
11 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js">
</script>
12 <script>
13 function cbFunction(data) {
14 alert('data: ' + JSON.stringify(data));
15 }
16
17 $("#btn_id").click(function () {
18 $("head").append("<script src='http://localhost:8080/
?callback=cbFunction'><\/script>");
19 });
21 </script>
22 </body>
23
24 </html>
//后端
01 var http = require('http');
02 var url = require('url');
03
04 http.createServer(function (request, response) {
05 var parsedUrl = url.parse(request.url, true);
06 var queries = parsedUrl.query;
07 var str = queries.callback + '(' + JSON.stringify({ 'hello':
'world' }) + ')';
08 response.end(str);
09 }).listen(8080);
10
11 console.log('Server running at http://127.0.0.1:8080/');