对于javascript程序员来说,发送ajax请求获取后台数据然后把数据和模板拼接成字符串渲染回DOM实现无刷新更新页面这样的操作可谓是轻车熟路。但众所周知,ajax有一个不好,就是不能跨域传输数据,而跨域传输有时候又是必须用到的,比如我们可能需要调用第三方网站提供的某些API来获取某些信息,提供给我们网站的用户。
 
例如,要开发一个天气应用,你可能需要调用第三方的天气API,这个时候就必然涉及到跨域请求数据,因为毕竟我们不可能为了开发一个天气应用就自己搭建一个天气API。在少数情况下,如果第三方网站的服务器上设置了CORS机制,这时是可以直接用ajax发送请求的。但在大多数情况下,第三方网站都没有这么慷慨,因为涉及到安全问题,不可能允许任意人都能自由调用自己网站的接口。这个时候jsonp就应运而生了。
 
在HTML中有这样一类标签,它们都有一个src属性,src属性的值是一个链接,当标签一被解析到DOM中,就会开始把src属性中的链接指向的资源下载到本文档,例如,设置了src的img标签会自动从src属性的链接中下载资源,下载的资源又会被浏览器解析成图片,加到DOM中;设置了src属性的iframe元素会从src链接里下载一张网页;设置了src属性的script元素也会自动从src链接里下载javascript代码并执行,而这个过程中DOM本身也是没有刷新的,更令人心动的是,src属性的链接根本没有同域的限制。这个原理就是实现JSONP的基石。
 
但是,我们想用它来实现跨域还很有难度。这个src属性的元素的加载和一般的ajax请求有一个很大的不同,回想一下,在一个典型的ajax请求中,我们可以完全控制请求的过程,我们可以对指定的网页实行open,可以设置请求头,可以指定响应的MIMEtype,关键的是,我们可以从xhr对象的responseText属性中获取响应数据,然后拼接模板,渲染DOM。但在img, iframe, script这些标签中呢,我们的控制权就被剥夺了,我们设置src属性,浏览器负责发送请求,服务器端返回的响应直接就被加载回DOM了,我们根本没有插手修改数据的机会。
 
怎么办呢?这就像向遥远的深空发射一艘飞船,当飞船远离我们几十光年的时候,我们就不太可能从地面对它发送实时控制信号了,更好的做法就是把指令提前写在飞船上,让它自动执行。
 
和飞船的例子一样,一个典型的jsonp过程就是:创建一个script标签,设置src属性,这个src属性中包括了目标API的地址,我们的查询字符串querystring,querystring中最最重要的是我们的“指令”,因为script标签src返回之后,我们并不能控制返回的结果,所以最好让服务器返回的时候自己执行我们想要执行的操作。这个“指令”也就是jsonp中的“p”了。
 
举一个栗子:
1.我需要某个数据,比如就按照前面讲的,天气数据吧,于是我构造查询url。
var script = document.createElement('script');
script.src = 'www.weather.fake/get/?province=hubei&city=wuhan&callback=instruction';
document.getElementsByTagName('head')[0].appendChild(script);
//先写好指令,即回调
function instruction(data){
console.log(data);
}
//注意这里的instruction就是我们告诉服务器的“指令”。我们跟服务器说,我需要province为hubei,city为wuhan的地方的天气数据,但由于数据返回后我自己不能处理,所以你返回数据的时候自己处理好了,具体怎么处理,我已经写在名字叫做instruction的指令里面了。
2.weather.fake的服务器收到我的请求,从数据库里一找,找到了数据。一看,还有个指令,于是它就执行instruction指令。说起来很高级,实际上也就是把返回的数据包裹在instruction函数里面(jsonp的p,padding)。服务器于是返回这样一个东西:
//response.js
instruction({
  "city":"wuhan",
  "weather":"cloudy"
})
 
3.服务器端的writeheader设置和浏览器端的accept设置会保证返回的东西会被浏览器解释成一个js文件,于是我们事先写好的指令instruction函数就得到了执行,整个jsonp过程就完成了。
 
需要注意的几点:
 
1.返回的js文件是在全局作用域执行的,所以你要保证你写的回调函数instruction在全局作用域里。
 
 
2.这里的callback=instruction。其中,callback只是一个普通的querystring,是你和服务器事先约定的,不同API提供方,名字也不同,有的可能就叫cb,等等。至于instruction,你爱写什么写什么,但要保证和你写的回调处理函数名字一致。我这里为了方便理解,就写instruction了。
 
余论:ajax跨域,危险在哪里?
有些人说,禁止ajax跨域,是为了防止攻击者利用它向自己的服务器发送敏感信息(例如cookie等等),这显然是错误的。对于一个已经被注入攻击代码的网站,攻击者如果只是想向自己的服务器发送信息而已,就算不用ajax,也完全可以用img等标签直接向自己的服务器执行get请求发送数据,况且创建一个img标签可比写一个完整的ajax过程简单多了,根本用不着兴师动众,也就是说,单向GET请求ajax并没有优势。
 
为什么要限制ajax,因为它太强大了。看看CORS机制,它规定的是服务器方面的接受白名单。也就是说,由服务器来决定可以接受哪些客户可以向它请求数据。说明跨域限制主要是为了保证服务器端安全的。
 
一般能用src做到的,ajax都能做到,ajax能做到的src却不一定能够做到。例如src只能发起get请求,但ajax能发起任意类型的请求。
 
举个栗子,某博客网站的删除文章功能API可能必须要用DELETE方法发送请求才能执行,这个时候攻击者如果只用src构造请求就无能为力了,但ajax却可以轻易模拟用户动作。这个时候禁止跨域就显得很重要了。
 
具体过程:假设我的攻击网站是www.evil.com。而一个允许CORS跨域传输ajax的博客网站是www.blog.com。该博客网站中,当用户点击了删除按钮时,就会向服务器发送DELETE请求。具体为:www.blog.com/user/delete(?id=10000)(由于是DELETE方法,实际上querystring是不会附在url上的,这里为了便于说明而已。)这个时候,假如用户访问我的evil.com网站,而我在我网站的脚本里写ajax:
$.ajax({
url:'www.blog.com/user/delete',
method:'delete',
data:{id:10000},
})
这样是能成功的,因为当发送ajax时,会自动带上用户在www.blog.com的cookie,而请求方法又合法,所以完全能取得blog.com服务器的信任,也就能不知不觉地删除用户在blog.com上写的文章。

简单理解jsonp原理的更多相关文章

  1. 简单透彻理解JSONP原理及使用

    首先提一下JSON这个概念,JSON是一种轻量级的数据传输格式,被广泛应用于当前Web应用中.JSON格式数据的编码和解析基本在所有主流语言中都被实现,所以现在大部分前后端分离的架构都以JSON格式进 ...

  2. 深入理解JSONP原理——前端面试

    JSON和JSONP虽然只有一个字之差,但是它们俩是八竿子打不着的:JSON是一种数据交换格式,JSONP是非正式的跨域数据交换协议. 为什么说JSONP是非正式的传输协议呢?因为它就是利用了< ...

  3. 简单理解ThreadLocal原理和适用场景

    https://blog.csdn.net/qq_36632687/article/details/79551828?utm_source=blogkpcl2 参考文章: 正确理解ThreadLoca ...

  4. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  5. 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制

    [原创]分布式之数据库和缓存双写一致性方案解析(三)   正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...

  6. 简单的jsonp实现跨域原理

    什么原因使jsonp诞生?  传说,浏览器有一个很重要的安全限制,叫做"同源策略".同源是指,域名,协议,端口相同.举个例子,用一个浏览器分别打开了百度和谷歌页面,百度页面在执行脚 ...

  7. input屏蔽历史记录 ;function($,undefined) 前面的分号是什么用处 JSON 和 JSONP 两兄弟 document.body.scrollTop与document.documentElement.scrollTop兼容 URL中的# 网站性能优化 前端必知的ajax 简单理解同步与异步 那些年,我们被耍过的bug——has

    input屏蔽历史记录   设置input的扩展属性autocomplete 为off即可 ;function($,undefined) 前面的分号是什么用处   ;(function($){$.ex ...

  8. mDNS 原理的简单理解

    转自:http://www.binkery.com/post/318.html mDNS 原理的简单理解 mDNS multicast DNS , 使用5353端口. 在局域网内,你要通过一台主机和其 ...

  9. mDNS原理的简单理解——每个进入局域网的主机,如果开启了mDNS服务的话,都会向局域网内的所有主机组播一个消息,我是谁,和我的IP地址是多少。然后其他也有该服务的主机就会响应,也会告诉你,它是谁,它的IP地址是多少

    MDNS协议介绍 mDNS multicast DNS , 使用5353端口,组播地址 224.0.0.251.在一个没有常规DNS服务器的小型网络内,可以使用mDNS来实现类似DNS的编程接口.包格 ...

随机推荐

  1. cout 按进制数出

    头文件: #include<iostream> #include<iomanip> //setbase() #include<bitset> //bitset< ...

  2. linux find-在指定目录下查找文件

    推荐:更多Linux 文件查找和比较 命令关注:linux命令大全 find命令用来在指定目录下查找文件.任何位于参数之前的字符串都将被视为欲查找的目录名.如果使用该命令时,不设置任何参数,则find ...

  3. 【nginx】记录nginx+php-fpm实现大文件下载排坑的过程

    先上一段代码,支持大文件下载和断点续传,代码来源互联网. set_time_limit(0); // 省略取文件路径的过程,这里直接是文件完整路径 $filePath = get_save_path( ...

  4. Mongodb慢查询笔记 (Mongodb slow query log)

    -- =========================== -- mongodb slow query log -- =========================== Reference: h ...

  5. [luoguP1072] Hankson 的趣味题(数论)

    传送门 由题意得 gcd(x, a0) = a1 ——> gcd(x / a1, a0 / a1) = 1 lcm(x, b0) = b1 ——> x * b0 / gcd(x, b0) ...

  6. 【BZOJ4199&UOJ131】品酒大会(后缀数组,并查集)

    题意: 两杯“r相似” (r>1)的酒同时也是“1 相似”.“2 相似”.…….“(r−1) 相似”的. n<=300000 abs(a[i])<=10^9 思路:对于i,j两个后缀 ...

  7. 在代码动态设置RelativeLayout的属性,比如layout_below

    ( (RelativeLayout.LayoutParams)holder.ivLvDivider.getLayoutParams()).addRule(RelativeLayout.BELOW, R ...

  8. nyoj_278_排队_201403282135

    排队 时间限制:3000 ms  |  内存限制:65535 KB 难度:1   描述 周末了,软件ACM的队员准备玩玩游戏,娱乐一下,CY想了一个好主意,所有队员站成一个圈,从1开始报数,凡是报出指 ...

  9. 模拟赛 Problem 3 经营与开发(exploit.cpp/c/pas)

    Problem 3 经营与开发(exploit.cpp/c/pas) [题目描述] 4X概念体系,是指在PC战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以“EX”为开头的英语单词. eXpl ...

  10. Cocos2d-x 3.x 图形学渲染系列十一

    笔者介绍:姜雪伟.IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...