跨域

505 阅读3分钟

在项目开发中,如果所有的接口都是在访问域名下的接口,不需要跨域,我们要用多个服务上不同接口的时候,这就需要跨域,如果不跨域接口请求不成功的,那么

什么是跨域

跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。

那么什么是同源策略

同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

同源的定义

如果两个 URL 的 protocol、port (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源

比如:

http://store.company.com/dir2/other.html	同源	只有路径不同
http://store.company.com/dir/inner/another.html	同源	只有路径不同
https://store.company.com/secure.html	失败	协议不同
http://store.company.com:81/dir/etc.html	失败	端口不同 ( http:// 默认端口是80)
http://news.company.com/dir/other.html	失败	主机不同


跨域的实现的方式

1.CORS 跨域资源共享

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。 

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

(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

非简单请求是那种对服务器有特殊要求的请求,

比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

响应头添加Access-Control-Allow-Origin字段值这个值可以是*表示接受任意域名的请求,也可以是指定域名

html 代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div class="container">
      <div class="btn" onclick="getText()">获取数据</div>
      <div class="text"></div>
  </div>
  <script src="https://cdn.bootcss.com/jquery/3.5.0/jquery.js"></script>
  <script>
   var url = 'http:127.0.0.1:8082'
   function getText(){
        $(".text").load(url)
    }
  </script>
</body>
</html>

用node写的服务,html打开是本地域名,请求127.0.0.1:8082服务器,因为不是同一域名,端口号,所以请求属于跨域

//引入http模块
var http = require("http");
//设置主机名
var hostName = '127.0.0.1';
//设置端口
var port = 8082;
//创建服务
var server = http.createServer(function(req,res){
    res.setHeader('Content-Type','text/plain');
    res.end("hello nodejs");
});
server.listen(port,hostName,function(){
    console.log(`服务器运行在http://${hostName}:${port}`);
})

执行的结果


服务器请求头设置Access-Control-Allow-Origin,这样就可以访问到

var server = http.createServer(function(req,res){
    res.setHeader('Content-Type','text/plain');
    res.setHeader('Access-Control-Allow-Origin',"*")
    res.end("hello nodejs");
});

2.jsonp的方式

虽然因为同源策略的影响,不能通过XMLHttpRequest请求不同域上的数据(Cross-origin reads)。但是,在页面上引入不同域上的js脚本文件却是可以的(Cross-origin embedding)。因此在js文件载入完毕之后,触发回调,可以将需要的data作为参数传入 

node服务

//引入http模块
var http = require("http");
var Url = require("url")
//设置主机名
var hostName = '127.0.0.1';
//设置端口
var port = 8089;
//创建服务
var server = http.createServer(function(req,res){
    var path = req.url;
    var params = parseUrl(Url.parse(path).query);
    console.log(params, 'params')
	var data = {name:"zhou",age:20};
    var script = params.func+"("+JSON.stringify(data)+")";
    console.log(script, 'script')
	res.write(script);
	res.end();
});
server.listen(port,hostName,function(){
    console.log(`服务器运行在http://${hostName}:${port}`);
})

//解析urlparseUrl
function parseUrl(url){
	var obj = {};
	var urls = url.split("&");
	for(var key in urls){
		var keyVal = urls[key].split("=");
		obj[keyVal[0]] = keyVal[1];
	}
	return obj;
}

html

<!DOCTYPE html>
<html>
	<head>
		<title>JSONP</title>
		<meta charset="utf-8">
	</head>
	<body>
		<script>
			function showPersion(data){
				console.log("name: "+data.name+","+"age: "+data.age)
			}
		</script>
		<script src="http://127.0.0.1:8089?func=showPersion"></script>
	</body>
 
</html>

可以请求到服务器的数据

JSONP的优缺点

 优点:兼容性好(兼容低版本IE)

 缺点:

1.JSONP只支持GET请求;

 2.XMLHttpRequest相对于JSONP有着更好的错误处理机制

以上的两种跨域的方式是常用的两种方式,在实际的项目中也可以使用ngix代理