浏览器做为请求方与被请求方的域名、协议、端口三者中有一个不一样即被称做跨域。javascript
那么为何会有跨域呢?那要从同源提及。html
两个 url 的域名、协议、端口都相同,称为两个 url 同源。 同源是浏览器的安全限制,默认只有同源的两个网站才能互相获取数据。 若是没有同源限制,不一样网站之间能够共享 cookie,攻击者能够直接获取 cookie 发起 CSRF(跨站请求伪造)攻击;接口随便调用,致使数据泄漏或被删。前端
跨域的解决方案有:script 等标签、JSONP、iframe、node 请求转发、CORS、nginx 反向代理等java
img、link、script 标签经过 src 或 href 属性支持访问跨域资源,一般为 cdn 资源、第三方包资源。node
<img src="xxx" />
<link href="xxx" />
<script src="xxx"></script>
复制代码
jsonp 算是 script 标签跨域的一种变体,经过在 script 标签的 src 属性后面加上 callback 字段实现跨域请求数据。webpack
<script> function getMenuData(data) { // 根据data渲染菜单 } </script>
<script src="http://www.a.com/data?callback=getMenuData"></script>
复制代码
MenuData({ status: "success", data: ["menu1", "menu2"] });
复制代码
客户端和服务端在开发阶段作好数据约定,因为它仅支持 get 请求,如今使用场景已经不多了。nginx
iframe 的 postMessage 方法 自然支持跨域通讯,iframe 内外的页面能够采用不一样源的 url。web
<iframe src="www.b.com" ><iframe>
<script> window.addEventListener("message", function (event) { console.log(event.data); }); </script></iframe
></iframe
>
复制代码
window.postMessage(message, "http://www.a.com");
复制代码
使用 nodejs 建立一个 中转 server, 请求经过访问 node server 转发到目标地址, 突破跨域限制。 从一开始的:ajax
A => C A请求C
A <= C C响应A
复制代码
转变为:json
A => B => C A请求B,B请求C
A <= B <= C C响应B,B响应A
复制代码
var koa = require("koa");
var proxy = require("koa-proxy");
var app = koa();
app.use(
proxy({
host: "http://www.a.com", // 最终访问的api地址
})
);
app.listen(3000);
复制代码
tips:同源策略是浏览器的限制,不是服务器的限制。 此方法经常使用于开发时,后端不提供跨域支持,由前端解决跨域限制。如今 webpack-dev-server 自带 proxy,再也不须要本身启动额外的 server,只用添加配置就行,以下:
'/api': {
target: 'https://http://123.123.123.1:8080',
changeOrigin: true,
secure: false,
pathRewrite: {
'^/api': '/api'
}
}
复制代码
cors 是服务端配置,配置跨域资源请求以后,服务端资源可被跨域请求。主要为如下几个响应头:
值得注意得是,服务端设置了 CORS 以后须要针对 options 方法的请求作单独处理。
options 请求是浏览器主动泛起的一个刺探请求。 发送简单请求时浏览器不会生成刺探请求,发送复杂请求时会先发送一个嗅探请求,请求方法为 options,待刺探请求成功返回后才发送真正的请求。 嗅探请求的做用是:提早将实际请求所使用的方法和会携带的首部字段发送给服务器,防止对服务器数据产生反作用。 options 请求产生的请求头
origin: http://www.client.com
Access-Control-Allow-Methods: put...
Access-Control-Allow-Headers: Content-type...
复制代码
简单请求 知足如下条件的请求:
请求方法为 HEAD、GET、POST 中的一种,
请求头不超过如下几个:
nginx 反向代理是指客户端访问服务器路径 /api 地址时,服务器将 路径/api 下的请求都代理到指定的服务下面,原理和借用 nodejs 实现请求转发是同样的。
location /api/ {
proxy_pass http://123.123.123.1:8080/api/;
index index.html index.htm;
}
复制代码
跨域和同源其实不难,主要是要能结合理论解决平常遇到的问题:好比
Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource 你能很快定位问题是服务端没有设置跨域致使的。
Mixed content: the page at 'www.xxx.com/' was loaded over HTTPS, but resquested an insecure prefetch resource 'www.ooo.com/'. This content should also be served over HTTPS 你能很快理解这是浏览器的安全限制。
是否是全部复杂请求都会发起 options 刺探请求?
不是的,options 请求能够设置缓存时间,在过时以前不会再发刺探请求
Access-Control-Max-Age: time
复制代码
关于浏览器安全限制、iframe父子页面间通讯还有不少内容,欢迎评论、点赞。 此文章为【js基础】系列文章,关注小姐姐,一块儿学一学!