Open rccoder opened 8 years ago
非常不错的一篇文章 给你点赞了
+1 总结的好
点赞
订阅一下
其实postMessage
,严格来说,应该属于跨窗口通信
CRFS 应该是 CSRF
@404io 谢谢指正,已经修改
棒棒的
非常棒!
虽然原文不是我写的,但转的文章最好还是加上(转)会比较好
@mishe 问一下原文是在哪里?
@mishe 这。。。虽然有相同的地方,但是也不能叫原文吧
@mishe 是的,参考资料我早已给出相关链接,你给的链接并不是原文链接
抱歉,没注意到参考链接。
mark
关于 JSONP 的有一点我想请教下博主您,比如我后台(node.js)拼接了如下代码返回给前台
const obj = {
"text": 'jsonp',
}
const callback = req.url.split('callback=')[1]
const json = JSON.stringify(obj)
const build = callback + `(${json})`
res.end(build)
前端代码:
function handleResponse(res) {
console.log(res) // {text: "jsonp"}
}
const script = document.createElement('script')
script.src = 'http://127.0.0.1:3000?callback=handleResponse'
document.head.appendChild(script)
正如您说的,是以拼接JSON方式(拼接字符串)返回给前台,但是是在什么时候将JSON转为函数的呢?望博主赐教
@MuYunyun 以 script 标签的方式引入了一段 JS (这段 JS 到底是怎么产生的不重要,能直接执行就好),这段 JS 就是可执行的。
类似于通过 createElement 加了 script,引用了一段 JS
callback({text: 'jsonp'})
引入的时候不就是可执行的么
😄 确实纠结在 JSON 数据是如何转换成 JS 代码的这个点上了,我姑且认为浏览器通过 JSONP 格式跨域得到的结果会这样处理吧
jsonp的响应中设置了content-type是javascript,浏览器因此会将返回内容解析为js脚本执行 | Luyao Hua 邮箱:13521904856@163.com |
---|
在2018年02月03日 22:13,MuYunyun 写道:
😄 确实纠结在 JSON 数据是如何转换成 JS 代码的这个点上了,我姑且认为浏览器通过 JSONP 格式跨域得到的结果会这样处理吧
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.
@bupthly 我对您这个解释做了个实验,在 response-headers 设置 Content-Type:text/plain
或者不设置 Contenty-Type
,浏览器照样会将返回内容解析为 js 脚本~
@MuYunyun 和 content-type 关系不大,你有没有好奇过为啥在 HTML 里通过
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
就能引入一个 $
的变量呢。。。
核心是 通过 script
引入
浏览器解析到是js文件会执行脚本的,$是脚本执行是挂到window上的啊
Luyao Hua 邮箱:13521904856@163.com |
---|
签名由 网易邮箱大师 定制
在2018年02月04日 17:14,Shangbin Yang 写道:
@bupthly 和 content-type 关系不大,你有没有好奇过为啥在 HTML 里通过
就能引入一个 $ 的变量呢。。。
核心是 通过 script 引入
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.
嗯了解了。 试了下,确实与content-type无关。
但是之前项目中有次遇到后端返回中content-type是text/plain时一直无法正常执行,后改成text/javascript后就可以了,不知道是什么原因?
Luyao Hua 邮箱:13521904856@163.com |
---|
签名由 网易邮箱大师 定制
在2018年02月04日 17:14,Shangbin Yang 写道:
@bupthly 和 content-type 关系不大,你有没有好奇过为啥在 HTML 里通过
就能引入一个 $ 的变量呢。。。
核心是 通过 script 引入
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.
@bupthly 只是说不大,还是有一定的关系的,可以参考:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
Note that text/plain does not mean any kind of textual data. If they expect a specific kind of textual data, they will likely not consider it a match. Specifically if they download a text/plain file from a element declaring a CSS files, they will not recognize it as a valid CSS files if presented with text/plain. The CSS mime type text/css must be used.
我总结下楼主您的意思是说通过 script 标签引用 jq 脚本将 $ 挂到全局上,然后类比 JSONP 也类似通过 script 标签引用从而将返回的callback(Obj)挂到全局。至于浏览器如何将callback(Obj)
这个 JSON
对象转成 JS 的我们可以不关心,把它当成一个黑盒。
@MuYunyun 不是... 前半部分对,后半部分不太t对...
我在红宝书587页,看到它介绍JSONP的优点有提到一句它的优点在于能够直接访问响应文本
,里面涉及到的知识点它没有深讲了,愿闻其详 😄
不要被 JSONP 这个名字误导啊,他只是一个名字而已。script 标签是开放性的,没有域名的限制,也就是说通过 script 标签引入的任何脚本,都能被执行。所以可以利用这个特性来绕过异步请求同源的限制。
思路很简单,就是你先在本地创建一个回调函数,姑且称为 callback ,然后利用 script 标签不管引入来自哪个域名的脚本,都可以调用 callback。而数据就通过给 callback 传递参数(一般都是json,当然字符串也可以),来达到跨域数据交换。所以 jsonp 要求后端返回的数据是 callback(Object) 这种类型的。
由于安全的原因,浏览器做了很多方面的工作,由此也就引入了一系列的跨域问题,需要注意的是:
跨域并非浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但是返回结果被浏览器拦截了。最好的例子是
CSRF
跨站攻击原理,请求是发送到了后端服务器无论是否跨域!注意:有些浏览器不允许从HTTPS的域跨域访问HTTP,比如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例1. JSONP
JSONP
的全称是 "JSON With Padding", 词面意思上理解就是 "填充式的JSON"。它不是一个新鲜的东西,隶属于JSON
的一种使用方法,或者说是一种使用模式,可以解决一些常见的浏览器端网页跨域问题。正如他的名称一样,它是指被包含在调用函数中的JSON,比如这样:
由于
jQuery
的一些原因,使得JSONP
常常与Ajax
混淆。实际上,他们没有任何关系。由于浏览器的同源策略,使得在网页端出现了这个“跨域”的问题,然而我们发现,所有的
src
属性并没有受到相关的限制,比如img
/script
等。JSONP
的原理就要从script
说起。script
可以执行其他域的js
函数,比如这样:显然,上面的代码是可以执行的,并且可以在console里面输出http://www.rccoder.net
利用这一点,假如b.js里面的内容不是固定的,而是根据一些东西自动生成的, 嗯,这就是JSONP的主要原理了。回调函数+数据就是
JSON With Padding
了,回调函数用来响应应该在页面中调用的函数,数据则用来传入要执行的回调函数。至于这个数据是怎么产生的,说粗鲁点无非就是字符串拼接了。
简单总结一下: Ajax 是利用 XMLHTTPRequest 来请求数据的,而它是不能请求不同域上的数据的。但是,在页面上引用不同域的 js 文件却是没有任何问题的,这样,利用异步的加载,请求一个 js 文件,而这个文件的内容是动态生成的(后台语言字符串拼接出来的),里面包含的是 JSON With Padding(回调函数+数据),之前写的那个函数就因为新加载进来的这段动态生成的 js 而执行,也就是获取到了他要获取的数据。
重复一下,在一个页面中,a.html这样写,得到 UserId 为 1823 的信息:
请求这个地址会得到一个可以执行的 JavaScript。比如会得到:
这样,a.html里面的
parseResponse()
这个函数就能执行并且得到数据了。等等,jQuery到底做了什么:
jQuery 让 JSONP 的使用API和Ajax的一模一样:
之所以可以这样是因为 jQuery 在背后倾注了心血,它会在执行的时候生成函数替换
callback=dosomthing
,然后获取到数据之后销毁掉这个函数,起到一个临时的代理器作用,这样就拿到了数据。JSONP 的后话:
JSONP的这种实现方式不受同源策略的影响,兼容性也很好;但是它之支持 GET 方式的清楚,只支持 HTTP 请求这种特殊的情况,对于两个不同域之间两个页面的互相调用也是无能为力。
2. CORS
XMLHttpRequest
的同源策略看起来是如此的变态,即使是同一个公司的产品,也不可能完全在同一个域上面。还好,网络设计者在设计的时候考略到了这一点,可以在服务器端进行一些定义,允许部分网络访问。CORS 的全称是 Cross-Origin Resource Sharing,即跨域资源共享。他的原理就是使用自定义的 HTTP 头部,让服务器与浏览器进行沟通,主要是通过设置响应头的
Access-Control-Allow-Origin
来达到目的的。这样,XMLHttpRequest 就能跨域了。值得注意的是,正常情况下的 XMLHttpRequest 是只发送一次请求的,但是跨域问题下很可能是会发送两次的请求(预发送)。
更加详细的内容可以参见:
CORS 的后话:
相比之下,CORS 就支持所有类型的 HTTP 请求了,但是在兼容上面,往往一些老的浏览器并不支持 CORS。
Desktop:
Mobile:
3. window.name
window.name 在一个窗口(标签)的生命周期之内是共享的,利用这点就可以传输一些数据。
除此之外,结合 iframe 还能实现更加强大的功能:
需要3个文件: a/proxy/b
proxy 是一个代理文件,空的就可以,需要和 a 在同一域下
4. document.domain
在不同的子域 + iframe交互的时候,获取到另外一个 iframe 的 window对象是没有问题的,但是获取到的这个window的方法和属性大多数都是不能使用的。
这种现象可以借助
document.domain
来解决。这样,就可以解决问题了。值得注意的是:
document.domain
的设置是有限制的,只能设置为页面本身或者更高一级的域名。document.domain的后话:
利用这种方法是极其方便的,但是如果一个网站被攻击之后另外一个网站很可能会引起安全漏洞。
5.location.hash
这种方法可以把数据的变化显示在 url 的 hash 里面。但是由于 chrome 和 IE 不允许修改parent.location.hash 的值,所以需要再加一层。
a.html 和 b.html 进行数据交换。
这样,利用中间的 c 层就可以用 hash 达到 a 与 b 的交互了。
6.window.postMessage()
这个方法是 HTML5 的一个新特性,可以用来向其他所有的window对象发送消息。需要注意的是我们必须要保证所有的脚本执行完才发送MessageEvent,如果在函数执行的过程中调用了他,就会让后面的函数超时无法执行。
http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html
http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html
捐赠
写文不易,赠我一杯咖啡增强一下感情可好?