同源策略
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。–引用自MDN
同源示例
域名 端口 协议三者一致才是同源
http://www.example.com:80 === http://www.example.com
https://www.example.com:443 === https://www.example.com
这里注意:这里是为了突出端口的区别才写上端口。在默认情况下 http 可以省略端口 80, https 省略 443。http://www.example.com:80 和 http://www.example.com 是一个东西。
如何解决跨域
CORS跨域资源共享
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器「不同的域、协议或端口」请求一个资源时,资源会发起一个「跨域 HTTP 请求」。
在CORS中有简单请求和复杂请求的概念:
简单请求
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain(application/json 为非简单请求)
这是为了兼容表单(form),(3)请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
(4)请求中没有使用 ReadableStream 对象。
凡是不同时满足上面条件的,就属于非简单请求。
代理

正向代理: 代理客户;
隐藏真实的客户,为客户端收发请求,使真实客户端对服务器不可见; 一个局域网内的所有用户可能被一台服务器做了正向代理,由该台服务器负责 HTTP 请求; 意味着同服务器做通信的是正向代理服务器;
反向代理: 代理服务器;
隐藏了真实的服务器,为服务器收发请求,使真实服务器对客户端不可见; 负载均衡服务器,将用户的请求分发到空闲的服务器上; 意味着用户和负载均…
共同点:
都是做为服务器和客户端的中间层
都可以加强内网的安全性,阻止 web 攻击
都可以做缓存机制,提高访问速度
区别:
正向代理其实是客户端的代理,反向代理则是服务器的代理。
正向代理中,服务器并不知道真正的客户端到底是谁;而在反向代理中,客户端也不知道真正的服务器是谁。
作用不同。正向代理主要是用来解决访问限制问题;而反向代理则是提供负载均衡、安全防护等作用。
node 正向代理:
相当于正向代理(forward)是一个位于客户端【用户A】和原始服务器(origin server)【服务器B】之间的服务器【代理服务器Z】,为了从原始服务器取得内容,用户A向代理服务器Z发送一个请求并指定目标(服务器B),然后代理服务器Z向服务器B转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
例如:我们在webpack中可以配置proxy来快速获取接口代理的能力:
//config/index.js...
module.export = {
devServer:{
port:8000,
proxy:{
"/api":{
target:"http://localhost:8080"
}
}
}
}
或者使用工具代理进行正向代理
nginx反向代理
配置hosts:
127.0.0.1 local.test
配置nginx
server {
listen 80;
server_name local.test;
location /api {
proxy_pass http://localhost:8080;
}
loaction / {
http://localhost:8080;
}
}
JSONP
JSONP 主要就是利用了 script 标签没有跨域限制的这个特性来完成的。
「使用限制」仅支持 GET 方法;
一个众所周知的问题,AJAX直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;
不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有src这个属性的标签都拥有跨域的能力,比如
于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、Web socket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;
恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被JS原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;
这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。
客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。
为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
具体例子:
1)我们知道,哪怕跨域js文件中的代码(当然指符合web脚本安全策略的),web页面也是可以无条件执行的。
远程服务器remoteserver.com根目录下有个remote.js文件代码如下:
alert('我是远程文件');
本地服务器localserver.com下有个jsonp.html页面代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
</head>
<body></body>
</html>
毫无疑问,页面将会弹出一个提示窗体,显示跨域调用成功。
2)现在我们在jsonp.html页面定义一个函数,然后在远程remote.js中传入数据进行调用。
jsonp.html页面代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
// 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body></body>
</html>
remote.js文件代码如下:
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
这个例子中客户端动态生成了动态查询的链接,把自己想要的数据拼进了url里,我们看到调用的url中传递了一个code参数,告诉服务器我要查的是CA1998次航班的信息,而callback参数则告诉服务器,我的本地回调函数叫做flightHandler,所以请把查询结果传入这个函数中进行调用。
而服务器的这个叫做flightResult.aspx的页面生成了一段这样的代码描述给了客户端。这就是jsonp的全过程。
总结原生JS实现JSONP的步骤
2.3.1 客户端
定义获取数据后调用的回调函数
动态生成对服务端JS进行引用的代码
设置url为提供jsonp服务的url地址,并在该url中设置相关callback参数
创建script标签,并设置其src属性
把script标签加入head,此时调用开始。
2.3.2 服务端
将客户端发送的callback参数作为函数名来包裹住JSON数据,返回数据至客户端。
AJAX与JSONP的异同:
AJAX和JSONP这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jQuery和extjs等框架都把JSONP作为AJAX的一种形式进行了封装;
但AJAX和JSONP其实本质上是不同的东西。AJAX的核心是通过XmlHttpRequest获取非本页内容,而JSONP的核心则是动态添加
所以说,其实AJAX与JSONP的区别不在于是否跨域,AJAX通过服务端代理一样可以实现跨域,JSONP本身也不排斥同域的数据的获取。
还有就是,JSONP是一种方式或者说非强制性协议,如同AJAX一样,它也不一定非要用JSON格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用JSONP提供公开服务。
总而言之,JSONP不是AJAX的一个特例,哪怕jQuery等巨头把它封装进了AJAX,也不能改变这一点!
Websocket
WebSocket 规范定义了一种 API,可在网络浏览器和服务器之间建立“套接字”连接。简单地说:客户端和服务器之间存在持久的连接,而且双方都可以随时开始发送数据。这种方式本质没有使用了 HTTP 的响应头, 因此也没有跨域的限制。
前端:
let socket = new Websocket("ws://loaclhost:8080");
socket.onopen = function() {
socket.send('hahah')
}
socket.onmessage = function(e) {
console.log(e.data)
}
后端:
const Websocket = require("ws");
const server = new WebSocket.Server({port:8080});
server.on("connection",function(socket) {
socket.on("message",function(data) {
socket.send(data)
)}
)}
window.postMessage
window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
用途
1.页面和其打开的新窗口的数据传递
2.多窗口之间消息传递
3.页面与嵌套的 iframe 消息传递
用法
详细用法看 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow: 其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message: 将要发送到其他 window 的数据。
targetOrigin: 通过窗口的 origin 属性来指定哪些窗口能接收到消息事件.
transfer(可选) : 是一串和 message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权
示例:
// index.html
<iframe
:src="http://localhost:8080"
frameborder="0"
id="iframe"
onload="load()">
</iframe>
<script>
function load() {
iframe.contentWindow.postmessage('hahaha','http://loaclhost:8080')
window.onmessage = e=>{
console.log(e.data)
}
}
</script>
//another.html
<div>hello</div>
<script>
window.onmessage = e =>{
console.log(e.data) // hahaha
}
e.source.postMessage(e.data,e.origin)
</script>
doucument.domain + iframe
「该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式」。 只需要给页面添加 document.domain =‘test.com’ 表示二级域名都相同就可以实现跨域。
此方法可以用于cookie的跨域,服务器也可以在设置Cookie的时候,指定Cookie的所属域名为一级域名,
www. baidu. com .
三级域 二级域 顶级域 根域
//a.test.com
<body>
helloa
<iframe src="http://b.test.com/b.html"
frameborder="0"
onload="load"
id="frame"
>
</iframe>
</body>
<script>
document.domain = "test.com"
function load() {
console.log(frame.contentWindow.a);
}
</script>
// b.test.com
<body>
hellob
<script>
document.domain = "test.com";
var a = 100;
</script>
</body>
window.location.hash + Iframe
实现原理
原理就是通过 url 带 hash ,通过一个非跨域的中间页面来传递数据。
实现流程
一开始 a.html 给 c.html 传一个 hash 值,然后 c.html 收到 hash 值后,再把 hash 值传递给 b.html,最后 b.html 将结果放到 a.html 的 hash 值中。 同样的,a.html 和 b.htm l 是同域的,都是 http://localhost:8000,而 c.html 是http://localhost:8080
// a.html
<iframe src="http://localhost:8080/hash/c.html#name1"></iframe>
<script>
console.log(location.hash);
window.onhashchange = function() {
console.log(location.hash);
};
</script>
// b.html
<script>
window.parent.parent.location.hash = location.hash;
</script>
// c.html
<body></body>
<script>
console.log(location.hash);
const iframe=document.createElement("iframe");
iframe.src="http://localhost:8000/hash/b.html#name2";
document.body.appendChild(iframe);
</script>
.window.name + Iframe
window 对象的 name 属性是一个很特别的属性,当该 window 的 location 变化,然后重新加载,它的 name 属性可以依然保持不变。
即这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。
其中 a.html 和 b.html 是同域的,都是http://localhost:8000,而 c.html 是http://localhost:8080
// a.html
<iframe
src="http://localhost:8080/name/c.html"
frameborder="0"
onload="load()"
id="iframe"
></iframe>
<script>
let first = true;
// onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
function load() {
if (first) {
// 第1次onload(跨域页)成功后,切换到同域代理页面
iframe.src = "http://localhost:8000/name/b.html";
first = false;
} else {
// 第2次onload(同域b.html页)成功后,读取同域window.name中数据
console.log(iframe.contentWindow.name);
}
}
b.html 为中间代理页,与 a.html 同域,内容为空。
// b.html
<div></div>
// c.html
<script>
window.name = "哈哈哈";
</script>
通过 iframe 的 src 属性由外域转向本地域,跨域数据即由 iframe 的 window.name 从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
1954

被折叠的 条评论
为什么被折叠?



