-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
浅谈浏览器端JavaScript跨域解决方法 #5
Comments
非常不错的一篇文章 给你点赞了 |
+1 总结的好 |
点赞 |
订阅一下 |
其实 |
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
引入的时候不就是可执行的么 |
😄 确实纠结在 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 设置 |
@MuYunyun 和 content-type 关系不大,你有没有好奇过为啥在 HTML 里通过 <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script> 就能引入一个 核心是 通过 |
浏览器解析到是js文件会执行脚本的,$是脚本执行是挂到window上的啊
| |
Luyao Hua
邮箱:13521904856@163.com
|
签名由 网易邮箱大师 定制
在2018年02月04日 17:14,Shangbin Yang 写道:
@bupthly 和 content-type 关系不大,你有没有好奇过为啥在 HTML 里通过
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
就能引入一个 $ 的变量呢。。。
核心是 通过 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 src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
就能引入一个 $ 的变量呢。。。
核心是 通过 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
|
我总结下楼主您的意思是说通过 script 标签引用 jq 脚本将 $ 挂到全局上,然后类比 JSONP 也类似通过 script 标签引用从而将返回的callback(Obj)挂到全局。至于浏览器如何将 |
@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
捐赠
写文不易,赠我一杯咖啡增强一下感情可好?
The text was updated successfully, but these errors were encountered: