举例URL: https://www.stuspy.com/mxsj/paperTest.html?id=5a56d694ac502e0042d73dce
- 协议部分:
https:
- 分隔符:
//
- 域名部分:
www.stuspy.com
- 端口部分:
跟在域名后面的是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口
- 文件名部分:
从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分。本例中的文件名是“paperTest.html”。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名
- 锚部分:
从“#”开始到最后,都是锚部分。锚部分也不是一个URL必须的部分
- 虚拟目录部分:
从域名后的第一个“/”开始到最后一个“/”为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分,本例的虚拟目录为“/mxsj/”
参数部分:从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。本例中的参数部分为“id=5a56d694ac502e0042d73dce”
概念:只要协议、域名、端口有任何一个不同,都被当作是不同的域。
跨域的几种情况
- 协议不同
- 域名相同,端口不同
- 域名与域名对应ip
- 域名不同
- 主域相同,子域不同
- 同一域名,不同二级域名
跨域解决方案
1.CORS(主要解决的是异域之间的传值)
跨源资源共享定义了在必须访问跨源资源时,浏览器与服务器该如何沟通。其背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是否应该成功。
- 对于客户端,我们还是正常使用xhr对象发送ajax请求。
- 对于服务器端,需要在 response header中设置
Access-Control-Allow-Origin
字段。
IE8 通过 XDomainRequest 对象支持CORS,其他浏览器通过 XHR 对象原生支持 CORS。
2.图像Ping
图像Ping——最常用于跟踪用户点击页面或动态广告曝光次数。有两个主要的缺点,一是只能发送GET请求,二是无法访问服务器的响应文本。因此,图像Ping只能用于浏览器与服务器间的单向通信。
3.JSONP
JSONP(JSON with padding的简写)——是一种基于文本的数据交换方式,或者叫做数据描述格式。jsonp通过动态<script>元素来使用的,使用时可以为src属性指定一个跨域URL,因为 JSONP 是有效的 JavaScript 代码,所以在请求完成后,即在 JSONP 响应加载到页面中以后,就会立即执行。
JSONP的优点:
在于能够直接访问响应文本,支持在浏览器与服务器之间双向通信。
JSONP的不足:
- 首先,JSONP 是从其他域中加载代码执行。如果其他域不安全,很可能会在响应中夹带一些恶意代码,而此时除了完全放弃 JSONP 调用之外,没有办法追究。因此在使用不是你自己运维的 Web 服务时,一定得保证它安全可靠。
- 其次,要确定 JSONP 请求是否失败并不容易。
4.window.postMessage()
window.postMessage()
方法被调用时,会在所有页面脚本执行完毕之后,向目标窗口派发一个 MessageEvent
消息。
message 的属性有:
data
:从其他 window 中传递过来的对象。
origin
:调用 postMessage
时消息发送方窗口的 origin . 这个字符串由 协议、“://“、域名、“ : 端口号”拼接而成。请注意,这个origin不能保证是该窗口的当前或未来origin,因为postMessage被调用后可能被导航到不同的位置
source
:对发送消息的窗口对象的引用; 可以使用它来在具有不同origin的两个窗口之间建立双向通信。
window.postMessage()安全问题
- 如果不希望从其他网站接收message,就不要为message事件添加任何事件侦听器
- 始终使用origin和source属性验证发件人的身份
// 消息发送方
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求页面</title>
</head>
<body>
<div>
<p>这里是2000端口</p>
<input type="text"/>
<button>发送信息</button>
<p style="text-align: left;">message : <span></span></p>
</div>
<iframe id="child" src="http://localhost:2001"></iframe>
<script>
var input = document.getElementsByTagName('input')[0];
var btn = document.getElementsByTagName('button')[0];
var frame = document.getElementById('child').contentWindow;
btn.onclick = function () {
var msg = input.value;
frame.postMessage('收到信息:' + msg + ' --from 2000 port!', 'http://localhost:2001');
}
</script>
</body>
</html>
// 消息接收方
// 注册message事件并绑定事件监听函数
if (window.addEventListener) {
window.addEventListener('message', receiveMessage, false);
} else {
window.attachEvent('message', receiveMessage);
}
function receiveMessage(event) {
// For Chrome, the origin property is in the event.originalEvent
var origin = event.origin || event.originalEvent.origin;
// 使用origin或source属性验证发件人的身份
if (origin !== "http://localhost:2000") { // http://localhost:2000为自己定义的地址
return;
}
// Do Something ...
var data = event.data;
console.log(data)
}
该跨域方法适合于同一页面的不同窗体(iframe)
5.document.domain(主要解决的是子域与父域之间的传值)
- 定义:domain 属性可返回下载当前文档的服务器域名。
- 局限性: 一级域名一致才可以使用document.domain进行跨域访问
- 注:一级域名又称顶级域名。一级域名中只含有一个“.”,且“.”左边要有内容,最后一个点的右边被称为一级域名,左边被称为二级域名,以此类推二级三级域名。
现有父域:http://b.com/b.com.html
要向子域:http://a.b.com/a.b.com.html
获取数据
两个域都设置如下:
document.domain = 'b.com'; //设置成主域
这样就解决了子域与父域间的跨域问题
6. 后端设置代理proxy跨域
var express = require('express');
var proxy = require('http-proxy-middleware');
var requestPort = 2000;
var app = express();
app.use(express.static(__dirname));
app.use('/api', proxy({target: 'http://localhost:2001/', changeOrigin: true}));
// changeOrigin设置为true,本地会虚拟一个服务端接收你的请求并代你发送该请求
// http://localhost:2000/api --> http://localhost:2001/api
app.listen(requestPort, function () {
console.log('Requester is listening on port '+ requestPort);
});
7.WebSocket跨域
Web Sockets 是一种与服务器进行全双工、双向通信的信道。与其他方案不同,Web Sockets 不使用HTTP 协议,而使用一种自定义的协议——WebSocket 通信
网友评论