阅读 223

JSONP为什么能跨域

最近开发很少遇到这个问题,因为大部分后台通过添加响应头解决了,但是最近公司新招的后台一时不知道咋解决,就深入了解了下跨域的前世今生、以及原理。

JSONP为什么能跨域

1.跨域的产生

由于浏览器同源策略的限制,非同源下的请求,都会产生跨域问题,jsonp即是为了解决这个问题出现的一种简便解决方案。同源策略即:同一协议,同一域名,同一端口号。当其中一个不满足时,我们的请求即会发生跨域问题。 例如:

  • http://www.abc.com:3000到https://www.abc.com:3000的请求会出现跨域(域名、端口相同但协议不同)

  • http://www.abc.com:3000到http://www.abc.com:3001的请求会出现跨域(域名、协议相同但端口不同)

  • http://www.abc.com:3000到http://www.def.com:3000的请求会出现跨域(域名不同)

2.突破跨域

在HTML中有几个标签是没有被同源策略限制的,比如:<img>、<script>、<link>这三个标签的src属性是可以请求非同源策略的资源并获取返回的。例如常见的通过外链引入Jquery库。所以可以通过<script>来创建获取服务器的返回结果。

jsonp就是使用同源策略这一“漏洞”,实现的跨域请求(这也是jsonp跨域只能用get请求的原因所在)。想象一下,既然是个get请求,那么服务端一定可以接收到,并做出反馈。ok,知道这两点之后,我们开始具体使用jsonp进行跨域请求。

3.跨域的实现

既然知道了跨域的产生的规避同源策略的原理,这时候就可以通过动态创建<script>,来获取服务端的返回信息。

  • 前端端代码如下:
<html>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  <body>
      <button id="btn">点击</button>
  </body>
  <script>
      $('#btn').click(function(){
			var frame = document.createElement('script');
			frame.src = 'http://localhost:3000/article-list?name=leo&age=30&callback=func';
			$('body').append(frame);
		});
		
		function func(res){
			alert(res.message+res.name+'你已经'+res.age+'岁了');
		}
  </script>
</html>
复制代码

这样就可以从服务端会接收到一个get请求,请求所带的参数是{name:leo,age:30},服务端返回的就是一个callback为func的函数。

  • node服务端
router.get('/article-list', (req, res) => {
  console.log(req.query, '123');
  let data = {
    message: 'success!',
    name: req.query.name,
    age: req.query.age
  }
  data = JSON.stringify(data)
  res.end('func(' + data + ')');
});
复制代码

这时候服务端查询完信息后,会把查询到的数据通过func({message:success,name:阿萨,age:30})这样的形式返回给前端。

JSONP为什么会执行callback

上面的代码通过后台返回后,相当于在<body>标签中又创建了个<script>标签,形式如下:

 <script>
    func({message:success,name:阿萨,age:30}) //后台JSONP返回的数据
 </script>
 <body></body>
 <script>
    $("#btn").click(function(){
    .......
    })
    function func(res){
	 alert(res.message+res.name+'你已经'+res.age+'岁了');
	}
 </script>
复制代码

所以相当于后台返回了一个js代码,以script标签的形式嵌入到html中,然后后执行已经提前声明好的函数方法。

为什么不能用POST

在MDN的CORS中又这样的描述: 某些请求不会出发CORS预检查请求。有GET,HEAD,POST。其中POST的 Content-Type必须为下面三种:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

一个POST请求通常是通过HTML 表单发送, 并返回服务器的修改结果. 在这种情况下, content type 是通过在<form>元素中设置正确的enctype属性, 或是在<input>\和<button>元素中设置formenctype属性来选择的: 所以当 POST 请求是通过除 HTML 表单之外的方式发送时,就必然会执行跨域检查。

上图第一个是通过ajax发送的请求,第二个是通过form表单发送的请求。可以看出,浏览器的同源策略是拦截的xhr这样的请求方式。

注:jsonp虽然也是get请求,但是没有调用XMLHttpRequest方法,所以不会执行跨域检查,JSONP本质是欺骗浏览器,规避调用XMLHttpRequest

结语

自己理解测试加查资料所梳理的小知识点,可能现在都用不到了,只是整理出来防止自己健忘。如有疑问,或者错误还请指出~

关注下面的标签,发现更多相似文章
评论