对jsonp原理理解

对于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上写的文章。

时间: 2024-12-15 04:53:31

对jsonp原理理解的相关文章

解决Ajax 跨域问题 - JSONP原理解析

解决Ajax 跨域问题 - JSONP原理解析 为什么会有跨域问题? - 因为有同源策略 同源策略是浏览器的一种安全策略,所谓同源指的是 请求URL地址中的 协议, 域名 和 端口 都相同,只要其中之一不相同就是跨域 同源策略主要为了保证浏览器的安全性 在同源策略下,浏览器**不允许**Ajax跨域获取服务器数据 http://www.example.com/detail.html 跨域请求: http://api.example.com/detail.html 域名不同 http://www.

AJAX(六)jsonp原理详解

一.什么是jsonp? 先别管什么叫jsonp,我们先来看一个小问题,看完这个问题你就知道jsonp是要解决什么问题的,自然也就明白什么是jsonp了. 问题: 之前做的例子如果在同一个域名下运行时是非常正常的,但如果这个数据接口是在A域名下,而使用了AJAX请求的静态页运行在B域名下,我们就会发现点击按钮发出请求时会报错.截个图来看看. 我们看到后台的一般处理程序运行的域名是 : http://localhost:64113 现在使用VS重新创建1个web项目,然后在这个使用AJAX方式发出请

跨域及JSONP原理

什么是跨域:a.com 域名下的js无法操作b.com或是c.a.com域名下的对象 为什么浏览器要引入跨域问题? 跨域问题来源于浏览器的同源策略,为啥要有这个策略呢? 为了安全.假设现在有a.com 和b.com 两个域,如果没有同源策略的限制,那么a.com就可以随随便便就去b.com 里面拿东西,甚至一些cookie信息(常用于存储登录信息),那么a.com只需要一段代码就可以获取你的cookie信息,从而冒充你的身份去登录网站. 当使用 AJAX 跨域访问资源 会受到同源策略影响,浏览器

POJ1523(求连用分量数目,tarjan算法原理理解)

SPF Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7406   Accepted: 3363 Description Consider the two networks shown below. Assuming that data moves around these networks only between directly connected nodes on a peer-to-peer basis, a

Ajax跨域:Jsonp原理解析

推荐先看下这篇文章:JS跨域(ajax跨域.iframe跨域)解决方法及原理详解(jsonp) JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容. JavaScript这个安全策略在进行多iframe或多窗口编程.以及Ajax编程时显得

JAVA 1.7并发之LinkedTransferQueue原理理解

昨天刚看完BlockingQueue觉得好高级啊,今天扫到1.7就发现了升级版.... 如果对内容觉得不够充分,可以去看http://www.cs.rochester.edu/u/scott/papers/2009_Scherer_CACM_SSQ.pdf 就是作者的论文啦,纯英文...比较难啃,但是我觉得逻辑上比看代码容易理解,其实代码什么u啊h啊看得很混 LinkedTransferQueue 起源: 我觉得是这样的,之前的BlockingQueue是对 读取 或者 写入 锁定整个队列,所以

JSONP原理及jQuery中的使用

JSONP原理 JSON和JSONP JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,用于在浏览器和服务器之间交换信息. JSONP(JSON With Padding),就是打包在函数调用中的的JSON(或者包裹的JSON). JSON是一种数据格式,JSONP是一种数据调用方式. 1 //JSON 2 3 { 4 5 “name”: “sb” 6 7 } 1 //JSONP 2 3 callback({ 4 5 “name”: “sb” 6 7 }

Java内存的原型及工作原理理解

一.java虚拟机内存原型 寄存器:我们在程序中无法控制. 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 堆:存放用new产生的数据 静态域:存放在对象中用static定义的静态成员 常量池:存放常量 非RAM存储:硬盘等永久存储空间. 二.常量池(constant pool) 常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据.除了包含代码中所定义的各种基本类型(如int.long等等)和对象型(如String及数组)的常量值(final)

ConcurrentHashMap源码解读及原理理解

ConcurrentHashMap结构图如下: ConcurrentHashMap实现类图如下: segment的结构图如下: package concurrentMy.juc_collections.hashMap; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.AbstractCollection; import java.