前端跨域(二):JSONP
上一篇文章 前端跨域(一):CORS 实现了跨域的一种解决方案,IE8 和其他浏览器分别通过 XDomainRequest 和 XHR 对象原生支持 CORS。这次我将补一补 Web 服务中也非常流行的一种跨域技术——JSONP,同时,将复用上次的前端跨域场景。
1. JSONP(JavaScript Object Notation with padding,填充式JSON/参数式JSON)
【简单理解】:JSONP = 回调函数(Padding) + 数据(JSON),可以将 Padding 理解为回调函数,JSONP 则为被包含在函数调用中的 JSON。
callback({ "name": "Nicholas" });
【原理】:Ajax 的跨域受到“同源策略”的限制,但是像 <script>
及 <img>
标签带有 src
属性,都可不受限制地其他域中加载资源,JSONP 则是通过动态 <script>
元素来使用的。
【实现方式】:回调函数是当响应到来时应该在页面中调用的函数,其名字一般在请求中指定。在请求完成后,即 JSONP 响应加载到页面中以后,就会立即执行。
function handleResponse(response) {
alert(response.city);
}
var script = document.createElement('script');
// 指定回调函数的名字为 handleResponse
script.src = 'http://freegeoip.net/json/?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);
【优点】:能够直接访问响应文本,支持在浏览器域服务器之间双向通信。
【缺点】:JSONP 从其他域中加载代码执行,存在安全隐患,因此,使用时需要保障web服务安全可靠。
2. 本地模拟 JSONP 跨域
接下来让我们来一步一步实现 JSONP,从中我们也将看到,JSONP 跟 AJAX 毫无关系。
(1)首先,如果不使用 JSONP,实现一个正常的函数调用:创建 2 个 <script>
标签,一个用来定义函数以便处理数据,另一个则用来进行函数调用。
(2)接着,我们将第二个 <script>
标签中的函数调用放到单独的 js
文件中,更改一下传入参数,进行验证。
(3)到此为止, callback
函数是在本地的 js
文件中被调用的。现在,假设这个 js
文件在服务端,需要通过请求才能获得,则给 <script>
标签指定相应的 src
即可。
Server 端:
var http = require('http');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
// 发送字符串,等客户端获得响应时,即会调用该函数
res.end("callback('This is the callback from server.')");
}).listen(8888);
(4)上面的回调函数是在服务端写死的,而现实的情况,应该是客户端以参数的形式将回调函数名称传递给服务端,服务端获取这个变量,从而进行调用。这样,服务端就不用关心这个回调函数的名称是否改变了,而且前端也可以自行定义回调函数的名称。
OK,既然要传参,就得约定参数 key 值,这也是JSONP中唯一需要前后端一起约定字段的地方。
Server:
var http = require('http');
var url = require('url');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
// 解析 url 参数
var params = url.parse(req.url, true).query;
// jsonpCallback 为前后端约定的字段,用于获取回调函数的名称
res.end(params.jsonpCallback + "('This is JSONP.')");
}).listen(8888);
(5)最后一步:为了提高代码的灵活性,实现 <script>
标签动态插入
<script>
// 定义回调函数
var cb = function(data) {
var oDiv = document.getElementById('content');
oDiv.innerHTML = data;
}
var url = 'http://localhost:8888?jsonpCallback=cb';
// 创建 script 标签,并设置其 src 属性
var script = document.createElement('script');
script.src = url;
// 插入 body,此时调用开始
document.body.appendChild(script);
</script>
瞧,整个过程,我们并没有用到 XHR 对象,只是利用了
<script>
的src
属性,因此 JSONP 与 AJAX 并不是一回事儿。
3. jQuery 实现 JSONP
jQuery 是前端经常使用的库,因此有必要了解 JSONP 在 jQuery 中的使用方式。
jQuery 将其包含在 $.ajax()
中,其中用到的具体有3个参数:
dataType(默认:none)
:预期服务器返回的数据类型('json', 'jsonp', 'xml', 'html', 'text')
jsonp(默认:“callback”)
: JSONP回调查询参数的名称,即前后端约定的字段名
jsonpCallback(默认:“jsonp{N}”)
:全局JSONP回调函数的字符串(或返回的一个函数)名。设置该项能启用浏览器的缓存。
Client:
var oDiv = document.getElementById('content');
// 定义回调函数
// 只是用于服务端获取名称,也可以自行实现,从而在 `success` 中进行调用
var cb = function() {};
$.ajax({
url: 'http://localhost:8888',
type: 'get',
dataType: 'jsonp', // 预期服务器返回的数据类型
jsonp: 'A_callback', // 指定回调查询参数的名称,即前后端约定的字段,默认为“callback"
jsonpCallback: 'cb', // 指定回调函数名称
cache: true,
success: function(data) { // jQuery 将 JSON 数据剥离出来,传入 success 和 error
console.log(data); // 'This is JSONP realized by jQuery.'
oDiv.innerHTML = data;
}
});
Server:不变
var http = require('http');
var url = require('url');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
// 解析 url 参数
var params = url.parse(req.url, true).query;
// A_callback 为前后端约定的字段,用于获取回调函数的名称
res.end(params.A_callback+ "('This is JSONP realized by jQuery.')");
}).listen(8888);
jsonp
可省略,或设置为false
,则查询参数就不会出现在 URL 中了,但是回调函数的名称需要前后端约定,因为无法从请求中获取回调函数的名称,后端只能将名称写死。
jsonpCallback
也可省略,jQuery 会自动生成一个随机字符串作为函数名,可以减少不必要的命名工作。
4. 参考
5分钟彻底明白 JSONP
Understanding JSONP
前端跨域(二):JSONP的更多相关文章
- 前端跨域解决方案: JSONP的通俗解说和实践
对于前端开发者而言,跨域是一个绕不开的话题.只有真正明白了各种方案的工作机制,才能针对性地进行跨域方案选型.本文将以探索者的视角,试图用最通俗的语言对一种"鼎鼎大名"的跨域解决方 ...
- 前端跨域之jsonp跨域
jsonp跨域原理 原理:因为通过script标签引入的js是不受同源策略的限制的(比如baidu.com的页面加载了google.com的js).所以我们可以通过script标签引入一个js或者一个 ...
- 前端跨域之Jsonp实现原理及.Net下Jsonp的实现
jsonp的本质是通过script标签的src属性请求到服务端,拿到到服务端返回的数据 ,因为src是可以跨域的.前端通过src发送跨域请求时在请求的url带上回调函数,服务端收到请求时,接受前端传过 ...
- 前端跨域之jsonp
demo1: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- 前端跨域问题相关知识详解(原生js和jquery两种方法实现jsonp跨域)
1.同源策略 同源策略(Same origin policy),它是由Netscape提出的一个著名的安全策略.同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正 ...
- jQuery(三) javascript跨域问题(JSONP解决)
加油~ --WH 一.什么是javascript跨域问题? 域:服务器域名,唯一标识(协议,域名,端口)必须保证一致,说明域相同 跨域:在一个服务器上,去访问另一个服务器上,并且得到另一个服务器返回回 ...
- 前端跨域(一):CORS
上周做了一个移动端表单提交的页面,其中涉及到了跨域问题,想来也是惭愧,因为之前一直都没有遇到过这个问题,因此都没有深入探索过,只是知道有哪几种方式,这次终于借这个机会可以把遗留的知识点补一补了. 1. ...
- 跨域Ajax -- jsonp和cors
跨域Ajax - jsonp - cors 参考博客: http://www.cnblogs.com/wupeiqi/articles/5703697.html http://www.cnblogs. ...
- 用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面
用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面 1.什么是跨域以及产生原因 跨域是指a页面想获取b页面资源,如果a.b页面的协议.域名.端口.子域名不同,或是a页面为ip地 ...
随机推荐
- 简述 JVM 垃圾回收算法
经典垃圾回收 标记-清除(Mark-Sweep) 研发园开了家新餐厅,餐厅老板在考虑如何回收餐盘时首先使用了最简单的方式,那就是服务员在顾客用餐的过程中,不定时的观察餐厅,针对用完餐的顾客记录他们的位 ...
- vue-swiper 基于Vue2.0开发 轻量、高性能轮播插件
vue-swiper 基于 Vue2.0 开发,基本满足大部分功能 轻量.高性能轮播插件.目前支持 无缝衔接自动轮播.无限轮播.手势轮播 没有引入第三方库,原生 js 封装,打包之后只有 8.2KB ...
- php处理ajax请求,ajax+php实现跨域
第一种方法通过设置Access-Control-Allow-Origin来实现跨域 1.首先要了解什么是域? 什么是域,简单来说就是协议+域名或地址+端口,3者只要有任何一个不同就表示不在同一个域.跨 ...
- python操作samba
最近在部署完xxl-job后,陆续将一些日常性执行的python脚本迁移到上面去:其中部分脚本涉及到对samaba的操作,先后尝试了pysmb.fs.smbfs.pysmbclient pysmb 安 ...
- 转:LRU算法
LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的,是根据页面调入内存后的使用情况进行决策了.由于无法预测各页面将来的使用情况,只能利用“最近 ...
- MarkdownPan2 简单使用指南
markdown 简单使用指南 一级标题 二级标题 三级标题加代码 四级标题 这里是加粗 这里是正文and English 888 这里有正文嵌入代码这种样式 这里是代码块 这种使用的代码块 还有引用 ...
- SecureCRT通过SSH2协议远程登录Ubuntu 18.04的过程总结
reference: https://blog.csdn.net/ghostar03/article/details/47441715 https://blog.csdn.net/u011186256 ...
- python builtin列表
Python Builtin function获得通过 python3 -c "import builtins;ff=open('test.txt','w');strlist=[(i+'\n ...
- php 跨域请求
执行要在跨域请求的服务器端对应的代码上增加下面的代码 <?php namespace Admin\Controller; // 指定允许跨域访问 header('Access-Control-A ...
- Spring源码学习(5)—— bean的加载 part 2
之前归纳了从spring容器的缓存中直接获取bean的情况,接下来就需要从头开始bean的加载过程了.这里着重看单例的bean的加载 if(ex1.isSingleton()) { sharedIns ...