同源策略
什么是同源?
如果两个页面的协议、域名、端口号 都相同。那么说这两个页面具有相同的源,也就是说同源。
什么是同源策略?
同源策略是浏览器提供的一个安全功能。
同源策略限制了从同一个源加载的文档或者脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。例如:可以防止恶意网站盗取用户的敏感信息、进行跨站点脚本攻击等行为。
不受同源策略影响的标签
<img src=''/>
<link href=''/>
<script src=''></script>
跨域问题
怎样解决跨域?
JSONP
利用script标签不受同源策略的影响,可以跨域引入外部资源的特性。
客户端传递一个callback参数给服务端,服务端返回数据时会将这个callback参数作为函数名包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
前端代码:
<script>
//callback参数
function onResponse(posts){
console.log(posts)
}
</script>
<!-- 调用 -->
<script src='http://localhost:9000/api'></script>
后端代码:
const http = require('http')
http.createServer((req,res)=>{
if(req.url==='/api'){
let posts= ['js','php']
res.send(`onResponse(${JSON.stringify(posts)})`)
}
}).listen(9000,()=>{
console.log(9000)
})
缺点: 只支持GET请求。
CORS
CORS全称 Cross-Origin Resource Sharing 即跨域资源共享 。
实现:
- 前端正常发送请求。
- 服务端在返回结果中加入响应头 Access-Control-Allow-Origin
请求分类:
- 简单请求
-
使用
get/post/head请求的 -
Content-type为text/plain或者multipart/form-data或application/x-www-form-urlencoded
- 复杂请求
复杂请求在正式通信前,增加一次option 预请求,通过该请求来指导服务端是否允许跨域请求。
- 使用
put/delete - 发送
json类型的数据 - 请求中有自定义的请求头
降域
此方案仅限主域相同,子域不同的跨域应用场景。通过双向设置document.domain的值,实现同域,解决跨域问题。
实现:
A页面域名: a.juejin.com
B页面域名: b.juejin.com
两个页面都加上 document.domain= 'juejin.com' ,即可突破浏览器同源策略的限制,来获取和操作对方的元素。
postMessage
window.postMessage() 方法可以安全地实现跨源通信,该 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
使用:
postMessage(data,origin)方法接受两个参数- data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用
JSON.stringify()序列化。 - origin:协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
- 发送方: 为目标元素添加事件处理程序,监听事件类型
- 接收方:为
window添加事件处理程序,事件类型为message
nginx代理跨域
nginx是一个高性能的HTTP的反向代理服务器,也是一个通用的TCP/UDP代理服务器。
实现思路:通过nginx配置开启一个代理服务器做跳板机,反向代理访问juejin2服务,并且顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
配置ngnix反向代理:
server {
listen 80; //监听的端口
server_name localhost;
location / {
root /Users/abc/dist/; //入口文件
index index.html index.htm;
}
location /api/ {
proxy_pass https://xxx.xxx.xxx/req/; //代理的地址
}
}
webSocket
websocket实现了浏览器和服务器的全双工通信,可以使用websocket协议完成跨域
Loacation.hash + iframe 跨域
实现原理: a和b跨域通信,通过中间页c来实现 。三个页面不同域之间使用iframe的location.hash传值,相同域使用js来通信
window.name + ifreame 跨域
实现原理: name值在不同的页面甚至不同的域名加载后依旧存在,并且可以支持非常产多个name值
通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。