梦回JSONP,带你解决跨域问题

78 阅读3分钟

为什么使用jsonp?首先要了解另外一个概念,什么是同源策略。

同源策略(Same-Origin Policy)是一种浏览器安全策略,用于保护不同源(origin)之间的网页资源之间的安全性。同源指的是两个URL的协议、域名和端口号都相同。

同源策略包含以下限制:

  1. Cookie、LocalStorage和IndexDB等资源只能由同源网页访问,防止恶意网站窃取用户的敏感信息。
  2. JavaScript的XMLHttpRequest(XHR)对象只能向同源发送请求,防止跨站点请求伪造(CSRF)攻击。
  3. DOM的限制,例如一个网页的Javascript代码无法获取或修改另一个来源的网页内容。

同源策略可以有效保护用户的信息安全和防止网络攻击,但在某些特定情况下可能会带来开发上的限制。为了实现不同源之间的交互,可以使用跨域资源共享(CORS、jsonp 、proxy)等技术方式来解决这个问题。今天着重讲一下jsonp方法

发起ajax请求

            $('#jsonp').click(function(){
                  $.ajax({
                        url: 'https://developer.duyiedu.com/edu/testJsonp',
                        dataType: 'jsonp',
                        method: 'post',
                        success: function(data){
                              console.log(data);
                        }
                  })
            })
            function fn(data){
                  console.log('tina')
                  console.log(data)
            }
   </script>

跨域会转为script标签,统一只能发送get请求,带src/href属性的都是get请求,这也是他的局限性。

<script src="https://developer.duyiedu.com/edu/testJsonp?callback=fn"></script>

在这里,我们最后直接返回一个 字符串 给客户端,<script> 标签将直接解析 字符串 里面的内容为 JavaScript 代码,即调用 fn()这个回调函数。所以我们的success对应的函数和fn函数输出data的结果一致。

jsonp的实现步骤:

  1. 改造url,?callback=fn_=126788999000这一串数字代表的是时间戳,目的就是为了生成唯一的函数名,避免冲突;
  2. 创建script标签,并且创建src属性;
  3. 后端收到请求和参数,把要返回的数据data通过 fn({处理好的数据})的形式返回;
  4. 浏览器收到jsonp返回的数据后,浏览器会当成真正的js 代码执行。就调用执行这个fn ;

⚠️调用只能在回调函数定义之后,不能在定义之前.

下面我们一起看一下jsonp的原理如何实现:

			ajax: function (options) {
				var url = options.url;
				var dataType = options.dataType;	//请求方式

				var targetProtocol = '';	//用户地址的协议
				var targetHost = '';	//用户地址的域名和端口

				if (url.indexOf('http://') == 0 || url.indexOf('https://') == 0) {
					//这个条件成立,说明用户传入的地址是一个绝对地址
					var targetUrl = new URL(url);	//把用户传进来的地址(字符串)变成一个真正的地址对象
					targetProtocol = targetUrl.protocol;	//返回地址对象的协议
					targetHost = targetUrl.host;	//返回地址对象的域名和端口
				} else {
					//代码走到这里说明,用户传入的地址是一个相对地址
					targetProtocol = location.protocol;	//返回地址对象的协议
					targetHost = location.host;	//返回地址对象的域名和端口
				}

				if (dataType != 'jsonp') {
					//这个条件成立说明用户的请求方式不是jsonp,那就直接返回
					return;
				}

				if (location.protocol == targetProtocol && location.host == targetHost) {
					//这个条件成立说明现在是同域
					//...
				} else {
					//不同域
					var callback = 'cb' + Math.floor(Math.random() * 100000);	//随机生成一个函数名

					//把生成的方法定义到window身上
					window[callback]=options.success;

					//生成script标签
					var script = document.createElement('script');
					if (url.indexOf('?') > 0) {
						//这个条件成立说明用户传的url里面有参数(带问号了)
						script.src = url + '&callback=' + callback;
					} else {
						script.src = url + '?callback=' + callback;
					}

					document.head.appendChild(script);
				}
			}
		}

这就是,基本的使用 JSONP 解决跨域问题的方案 ,在甲站点定义一个回调函数,以script标签的src属性方式向服务器发送网络请求,后端则修改数据后返回一个相同名称的回调函数并且参数的形式把数据返回,浏览器会解析为js代码然后执行这个回调函数,从而前端获取到后端返回的数据