前端跨域解决方案: JSONP的通俗解说和实践
对于前端开发者而言,跨域是一个绕不开的话题。只有真正明白了各种方案的工作机制,才能针对性地进行跨域方案选型。本文将以探索者的视角,试图用最通俗的语言对一种“鼎鼎大名”的跨域解决方案——JSONP的工作细节进行介绍。
需要说明的是,JSONP并不是仅仅需要前端处理即可,它还需要后端进行适当的配合设置。为此,本文将适当插入少量的node.js代码(koa框架),以便更直观的展现jsonp的工作原理。
问题引入:同源策略
什么是同源?
文档的来源相同,即协议、主机及端口均相同。
假设有一台域名是http://www.aaa.com
的服务器,它的根目录存放有index.html
文档,根目录下的js文件夹
下存放有main.js
文件。即两个文档的路径分别为:
http://www.aaa.com/index.html
http://www.aaa.com/js/main.js
这时,两个文档的协议、主机、端口均相同,均为:
协议:http
主机:www.aaa.com
端口:80
因为这里没有显示设置通信端口,因此默认是80,显然两者是同源的。假设将其中一个文档的通信协议换为https
,或者显示指定通信端口为10032
,或者放到另外一台服务器www.bbb.com
,这时两个文档都将变得不再同源。
本地文件的跨域问题
我们在本地新建一个test.html文件,使用浏览器打开,这时浏览器显示了该文档的url地址:
file:///C:/Users/lsz/Desktop/demo/test.html
协议:file
主机:本机
端口:不详,未查询到相关资料
显然,这时test.html
与前面两个文档采用的通信协议不同,所在的主机也不同,必然不属于同源文档。因而,当test.html文档视图访问前述两个文档时,会引发跨域问题。这也就是我们在本地随意新建一个文档,不做跨域处理时,无法从接口服务器获取数据的原因。
同源策略是客户端还是服务端的限制
它是客户端,即浏览器的限制。浏览器限制JS脚本不能读取不同源的文档。
为什么要设置同源策略
同源策略的限制,使得JS脚本不能读取不同源文档,可以防止脚本窃取其他页面的用户输入,从根本上是为了安全性。
为什么又需要跨域处理呢
- 同源策略虽然提高了安全性,但也会使得合法的请求也被拦截在外,这将使得我们的前端开发难以进行。
- 因此,我们需要寻求合适的解决方案来正常获取服务器数据,当然并不是要去改变浏览器本身的同源策略。
JSONP是如何解决跨域的
为什么叫JSONP
JSONP中文可以理解成填充式JSON
,P的英文是padding,填充之意
,也就是经过处理后的JSON。
那么,经过处理后的JSON与原JSON有何不同呢?
看这样一段JSON数据:
[1,2,{"buckle":"my shoe"}]
如果使用JSONP作为跨域技术,那么服务器
将不会直接返回以上JSON格式数据,而是会将其包裹,成为如下格式:
handleResponse([1,2,{"buckle":"my shoe"}])
在原先的基础上,加上了一对圆括号,并外面套上了一个函数名,成为新的JSON字符串。
JSONP是如何绕开同源策略的限制的
- JSONP是通过
<script>
元素绕开同源限制的。 <script>
元素不受同源策略的影响。
我们都知道,当给script的src属性指定特定的url地址,事实上,将会加载执行该url对应的JavaScript代码。
假设我们的服务器接口地址是http://www.aaa.com:3000/hello/word
,该接口地址的响应是handleResponse(‘Hello, world!’)
,这个响应是一个字符串。正常情况下,在浏览器地址栏直接输入http://www.aaa.com:3000/hello/word
,将会看到浏览器中显示handleResponse(‘Hello, world!’)
的字符串。
现在,我们在本地新建一个test.html文件,并增加一个script标签,给其src属性指定为上述地址,即:
<script src="http://www.aaa.com:3000/hello/world"></script>
创建一个处理响应的handleResponse函数:
<script>
function handleResponse(resp){
alert(resp);
}
</script>
完整示例:
<!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>
<script>
function handleResponse(resp){
alert(resp);
}
</script>
<script src="http://www.aaa.com:3000/hello/world"></script>
</body>
</html>
现在,在浏览器中打开本地文档test.html,将会看到,弹出一个窗口,窗口中显示hello,word!
。这表明我们的跨域已经成功!
以上的改进:JSONP通常动态创建script元素,前端指定函数名
在上面的案例中,存在两个问题:
- 对应于每一个服务端接口地址,都需要在html中写定一个script标签,指定其src属性,非常不灵活。能否不写定script标签,直接在JS代码中接收响应呢?
- 前端的处理函数
handleResponse
已经由服务端完全指定,想要接收服务端的数据,就必须编写名称为handleResponse的函数。那么是否能由前端自行命名响应处理函数呢?
答案是肯定的。
(一)js生成script标签
我们只需要在js代码中创建一个script标签,并设置其src属性即可。具体示例可见后面的代码。
(二)前端指定函数名
我们只需在前端请求中附加查询参数,在查询参数中指定处理函数名称,服务端接收查询参数,返回处理函数名称包裹的jsonp数据即可。koa服务器代码
示例如下:
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
router.get('/',async ctx =>{
const cb = ctx.query.callback;
ctx.status = 200;
ctx.body = `${cb}({ msg: '您正在访问koa服务器根目录!'})`;
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000,() => {
});
以上代码中,当前端访问服务器根目录时,服务器接收前端传递的callback查询参数,并将返回前端指定的函数名包裹的json字符串。
现在,本地文件test.html中前端代码
如下:
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://localhost:3000?callback=onBack';
document.head.appendChild(script);
// 回调执行函数
function onBack(res) {
alert(JSON.stringify(res));
}
</script>
如果我们的前端要改变处理响应的函数名,例如将onBack改为handleRes,只需做如下处理即可,而后端无需改动:
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://localhost:3000?callback=handleRes';
document.head.appendChild(script);
// 回调执行函数
function handleRes(res) {
alert(JSON.stringify(res));
}
</script>
前端跨域解决方案: JSONP的通俗解说和实践的更多相关文章
- jquery跨域解决方案JSONP
1.在互联网中我们的计算机是通过IP来定位的,但是IP比较难记忆,因此通过domain name(域名)来取代IP 2.什么是跨域? (1)默认浏览器为了安全问题,禁止了xmlhttprequest跨 ...
- 前端跨域之jsonp跨域
jsonp跨域原理 原理:因为通过script标签引入的js是不受同源策略的限制的(比如baidu.com的页面加载了google.com的js).所以我们可以通过script标签引入一个js或者一个 ...
- 前端跨域之Jsonp实现原理及.Net下Jsonp的实现
jsonp的本质是通过script标签的src属性请求到服务端,拿到到服务端返回的数据 ,因为src是可以跨域的.前端通过src发送跨域请求时在请求的url带上回调函数,服务端收到请求时,接受前端传过 ...
- 跨域解决方案 - JSONP
目录 1. 定义 2. JSONP 解决跨域 3. 应用场景 4. 代码演示 1. 定义 在HTML 中, script 标签有两个个性质: script 标签可以不受同源策略的限制去访问服务器资源, ...
- 彻底理解跨域解决方案JSONP
什么是同源策略? 同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略. 所谓同源是指,域名,协议,端口相同.当一个浏览器的两个tab页 ...
- 前端跨域之jsonp
demo1: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- 前端跨域(二):JSONP
上一篇文章 前端跨域(一):CORS 实现了跨域的一种解决方案,IE8 和其他浏览器分别通过 XDomainRequest 和 XHR 对象原生支持 CORS.这次我将补一补 Web 服务中也非常流行 ...
- 前端跨域问题相关知识详解(原生js和jquery两种方法实现jsonp跨域)
1.同源策略 同源策略(Same origin policy),它是由Netscape提出的一个著名的安全策略.同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正 ...
- 第十四节:Asp.Net Core 中的跨域解决方案(Cors、jsonp改造、chrome配置)
一. 整体说明 1. 说在前面的话 早在前面的章节中,就详细介绍了.Net FrameWork版本下MVC和WebApi的跨域解决方案,详见:https://www.cnblogs.com/yaope ...
随机推荐
- ARM.SchDoc图解
1.基准电压.CR1220电池 2.LCD 3.SPI 4.外部SAM 5.实时时钟 6.EEPROM 7.JTAG 8.复位
- Three.js 中的参数调试控制插件dat.GUI.JS - [Three.js] - [dat.GUI]
不论是处于特殊功能的需要,还是处于效果调试方便,我们可能都需要修改模型中的参数值.在Three.js中,谷歌提供了一个js库,即dat.GUI.js用于处理这种需求. 通过该库,我们就不需要通过手动修 ...
- 怎么用scratch做大鱼吃小鱼
行走代码不说了.出鱼代码大概就是 棋子被点击时 重复执行 移到x:从()到()任意选一个数,y一样 克隆自己 等待你想要的秒数.吃鱼代码就是 当作为克隆体启动是 重复执行 如果碰到()那么 删除克隆体 ...
- python通俗讲解闭包
通俗理解闭包 先来看看什么是闭包吧 闭包是引用了自由变量的函数.这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外.所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合 ...
- HTTP协议经典面试题整理及答案详解
无论你是Java.PHP开发者,还是运维人员,只要从事互联网行业,面试时都可能被问到HTTP协议相关知识.历时多天的呕心沥血,为你总结了HTTP协议的经典面试题.由于涉及内容比较繁杂不方便记忆,建议收 ...
- matplotlib IdentityTransform(原地变换)
2020-04-12 23:33:56 -- Edit by yangrayIdentityTransform继承于Affine2DBase类,它是一个高效实现原地变换的类.(不知道有什么用,变换前后 ...
- Spark 1.5 to 2.1.X
api差异参考官网地址:https://spark.apache.org/docs/2.1.1/sql-programming-guide.html#upgrading-from-spark-sql- ...
- SolrCloud(solr集群+zookeeper集群)
一.集群介绍 1. 什么是SolrCloud SolrCloud(solr 云)是Solr提供的分布式搜索方案,当你需要大规模,容错,分布式索引和检索能力时使用 SolrCloud.当一个系统的索引 ...
- stand up meeting 12/3/2015
part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 初始化弹窗的弹出位置并捕捉弹窗区域内的鼠标控制事件,初步解决弹窗的拖拽功能: 6 UWP对控件的支持各种看不懂,属性 ...
- SQL入门,就这么简单
随着时代的发展,人类活动产生的信息越来越多,大家常说,现在这个时代是大数据时代.在这样一个前提下,数据的存储成为我们必须要认真对待和研究的问题了.SQL(Structured Query Langua ...