1. 前言

jsonp是一种常用的跨域手段,和反向代理,服务端做跨域处理相比,jsonp更显得方便轻巧,因而被大量用来处理跨域的请求,那么,这种请求方式到底是用了什么黑魔法,来解决令我们头疼的跨域问题。

2. 原理

jsonp其实并没有用到什么黑魔法,能达到跨域这种效果,无非是利用script标签自身的跨域能力。我们知道,img,script,这种标签如果有相应的src,那么便会发起一个htttp请求来请求相应的资源,如果有script标签对应的路径是一个js文件,那么在下载完毕这个js之后会马上执行

<script type="text/javascript" src="www.somewhere.com/test.js"></script>

<!--此时会发起一个请求来获取test.js,下载完成之后会立即执行test.js-->

假设我们需要从’www.localhost.com’发起一个获取数据的请求’www.somewhere.com/getdata’,如果有我们以ajax来发起请求,那么由于浏览器同源保护策略的限制,该请求的返回值不会被浏览器所接受,这就是跨域问题。但是script这种标签会发起一个get请求,并且这个请求是不受同源策略限制的,如果有我们将’www.somewhere.com/getdata’以script标签来发送变成如下请求方式,那么是不是就不会有跨域问题了

<script type="text/javascript" src="www.somewhere.com/getdata"></script>

<!--需要这样一个script来发起get请求-->

答案是肯定的,这也是jsonp跨域的原理。但是同时,这里也出现了两个问题,第一,怎么使用script来发送请求,第二,请求得到的数据应该怎么在前端页面上接收并处理。对于第一个问题,我们一般会将script标签写在html文档中,当我们通常遇到的都会是动态请求,如果有我们还像原来一样把标签提前写好在html中,那么浏览器解析文档到这个script标签时就会立即发起请求,等我们想要用到这些数据时,再去找前面加载好的数据,这样显然太费时费力,不太灵活,而且页面上如果有很多请求,岂不是要提前些很多script标签在页面上,这样页面丑陋的根本没法看了。我们需要的是在请求服务的时候,再发起请求,那么我们完全可以用动态标签来实现,通多document.createElement来动态创建一个script标签,然后为其设置src属性,等请求完毕之后再将script标签移除,那么第一个问题便迎刃而解了。

let script = document.createElement('script');

srcipt.src = 'www.somewhere.com/getdata';

document.querySelector('head').appendChild(script);

但同时,这也产生了第二个问题,我们怎么知道请求什么时候完毕,请求回来的数据要怎么处理,以及,请求完毕之后要怎么清除标签。前面说到过,script标签下载完毕之后会立即执行(async和defer暂时按下不表),而我们的请求通常会返回一个json对象,然而json直接执行是要报错的,如{“name”: “柳轻侯”, “job”: “FE”}.如果花括号位于语句句首,那么花括号中的内容会被识别为一个语句块,外层的花括号会被直接忽略,如果是{name: ‘柳轻侯’, job: ‘FE’}这种形式可能并不会报错,因为即使忽略了花括号,name: ‘柳轻侯’也是一个合法的js语句,叫做标签语句,但是如有给标签语句加上引号,”name”: “柳轻侯”,这种形式却并不合法,因为标签语句不可以用引号引起来,然而json的key却必须用双引号引起来,所以直接返回一个json是不行的,必须返回一个可执行的js语句才行。而且一般来说我们需要请求结果来执行一些js逻辑操作,那么我们的操作逻辑要写在哪里,怎么跟返回结果相结合呢?这时候就需要callback出场了。我们可以把请求结果”包装”一下,将数据的处理逻辑写到一个函数中,然后在script的结果中来调用这个函数,把需要的数据传给这个函数,那么一切问题就都可以解决了。假设请求结果内容是{“name”: “柳轻侯”, “job”: “FE”},处理这个结果的函数叫callback

// 结果的处理,callback函数,必须在script请求之前就已经在页面上声明或赋值

function callback (data) {

console.log(data.name)

}

// 注意,script一定要返回一个js文件,文件内容是用回调函数将请求结果包装起来,形成函数调用的形式

// 文件内容

callback({"name": "柳轻侯", "job": "FE"})

但是如果页面上有多jsonp请求,总不能所有的回调函数都叫callback吧,那么这时候就需要指定回调函数的名字,不同的jsonp请求调用不同的回调函数。可以通过script请求将函数名传到服务端,然后服务端相应的将结果用此函数名包装,然后返回到前端,这样就可以按名称调用了。我们将请求做以简单的封装。

function getJSONP (url, callback) {

let script = document.createElement('script');

script.type= "type="text/javascript;

srcipt.src = url + '?callback=' + callback;

document.querySelector('head').appendChild(script);

}

如果有这时候有两个请求需要处理,”www.somewhere.com/getdata1”和”www.somewhere.com/getdata2”两个请求需要处理,请求结果分别是{“name”: “柳轻侯”, “job”: “FE”}和{“name”: “天棠”, “job”: “fe”},处理函数分别是dealData1和dealData2,那我们该怎么处理?

function getJSONP (url, callback) {

let script = document.createElement('script');

script.type= "type="text/javascript;

srcipt.src = url + '?callback=' + callback;

document.querySelector('head').appendChild(script);

}

const dealData1 = function (data) {

console.log('这是getData1的回调:' + data.name);

}

const dealData2 = function (data) {

console.log('这是getData1的回调:' + data.name);

}

// 分别发送请求

getJSONP('www.somewhere.com/getdata1', 'dealData1'); // www.somewhere.com/getdata1?callback=dealData1

getJSONP('www.somewhere.com/getdata2', 'dealData2'); // www.somewhere.com/getdata1?callback=dealData2

// 请求结果分别是

dealData1({"name": "柳轻侯", "job": "FE"})

dealData2({"name": "天棠", "job": "fe"})

//执行结果

这是getData1的回调: 柳轻侯

这是getData2的回调: 天棠

这时候两个结果会分别用传过去的callback来包装,然后输出不同的结果,这时候我们的需求基本上被满足了,最后还要处理的一点,每发一条请求,页面上被凭空创建了一个script标签,如果有请求很多,那么页面上就会多出很多无意义的标签(请求结束之后相应的标签就失去了意义),所以我们需要在请求处理结束之后清除创建的script标签。但是页面上还有别的script标签,必须只清除当前请求的jsonp生成的标签,如果将其他的script标签,可能就会造成其他的严重问题。由于每个jsonp的回调函数名称不一样,我们可以通过回调函数名来找出我们想要清除的script。

const dealData1 = function (data) {

console.log('这是getData1的回调:' + data.name);

// 处理完毕之后清除相应的script标签

let callbackName = arguments.callee.name;

document.querySelector('script[src*="callback=' + callbackName + '"]').remove();

}

3. jsonp的缺点

  • 只能发送get请求。因为script只能发送get请求
  • 需要后台配合。此种请求方式应该前后端配合,将返回结果包装成callback(result)的形式。

jsonp跨域的原理相关推荐

  1. .net学习之母版页执行顺序、jsonp跨域请求原理、IsPostBack原理、服务器端控件按钮Button点击时的过程、缓存、IHttpModule 过滤器...

    1.WebForm使用母版页后执行的顺序是先执行子页面中的Page_Load,再执行母版页中的Page_Load,请求是先生成母版页的控件树,然后将子页面生成的控件树填充到母版页中,最后输出 2.We ...

  2. JSONP跨域的原理解析

    JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略). ...

  3. JSONP跨域的原理解析及其实现介绍

    JSONP 即 Json padding ,JSONP跨域GET请求是一个常用的解决方案,下面我们来看一下JSONP跨域是如何实现的,并且探讨下JSONP跨域的原理 JavaScript是一种在Web ...

  4. javascript实现jsonp跨域问题+原理

    在工作中往往存在跨域的问题 ,跨域是什么概念就不在这里了,搜这类问题的肯定已经知道了.下面直接探讨jsonp跨域原理 jspon跨域原理: 1.动态创建一个script标签 var script = ...

  5. 深入理解jsonp跨域请求原理

    在进行网站开发的过程中经常会用到第三方的数据,但是由于同源策略的限制导致ajax不能发送请求,因此也无法获得数据.解决ajax的跨域问题有两种方法: 一.jsop 二.XMLHttpRequest2中 ...

  6. jsonp跨域的原理以及优缺点

    在开发测试中,难免会在不同域下进行跨域操作,出于安全性考虑,浏览器中的同源策略阻止从一个域上加载的脚本获取或者操作 另一个域下的文档属性,这时需要进行跨域的方式进行解决,如:使用jsonp ,ifra ...

  7. Ajax--同源策略,jsonp跨域传输原理(callback),

    什么是同源策略? 阮一峰的博客 同源策略 同源策略的解决方法: 跨域传输 img 标签的src是可以引入其他域名下的图片 script标签的src属性同理 ,也可以引入其他域名下的js文件,并执行 1 ...

  8. JSONP 跨域的原理

    搜所 JSON相比大家都已经很了解了,那么JSONP又是个什么鬼,JSONP是利用在页面中动态创建script节点的方法向不同域提交HTTP请求的方法称为JSONP,通俗的来说,就是在服务端输出JSO ...

  9. jsonp 跨域原理详解

    转载至:http://zha-zi.iteye.com/blog/1975116 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制 ...

  10. jsonp跨域原理及使用

    在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的.但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的. jsonp通过script标 ...

最新文章

  1. OpenGL的简单研究-开端
  2. Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks(更快的RCNN:通过区域提议网络实现实时)
  3. mysql清除数据痕迹_MySQL使用痕迹清理~/.mysql_history - milantgh
  4. ssm三大框架工作原理_蒸发器最常见的三大工作原理
  5. 杭州某知名xxxx公司急招大量java以及大数据开发工程师
  6. python3.6安装tensorflow gpu_tensorflow-gpu安装的常见问题及解决方案
  7. [APIO2010]特别行动队
  8. 【算法】剑指 Offer 66. 构建乘积数组
  9. kali卸载firefox_kali 安装最新firefox的悲惨经历
  10. Mysql学习总结(65)——项目实战中常用SQL实践总结
  11. linux怎么杀掉mpd进程,linux怎么样安装mpd进程管理器
  12. 程序员面试金典——1.1确定字符互异
  13. 什么是CMMI认证?
  14. 1600k 打印头测试软件,巧修LQ-1600K打印机打印头
  15. 上海电信中兴B860A 4K版破解
  16. IPD不仅是流程更是管理体系(附华为IPD培训资料)
  17. 剑灵灵动区服务器位置,《剑灵》这波电二合区,属实让我脑壳疼
  18. hdl_graph_slam的论文阅读
  19. pyecharts qq聊天记录数据可视化
  20. Tokio教程之select

热门文章

  1. LED发光原理(笔记)
  2. c语言字符程序示例,C语言程序设计实例大全
  3. Hadoop运维记录系列(十九)
  4. 502网关错误解决_“ HTTP 502错误的网关”错误和解决方案
  5. Mybatis-Plus实现逻辑删除
  6. 【转载】Oracle之同义词(SYNONYM)
  7. ARM 发布新一代 CPU 和 GPU,实现 20% 性能提升!
  8. android12.0(S) Launcher3 去掉抽屉
  9. 炼丹笔记三:数据增强
  10. 树莓派Python 按键实验