跨域
协议、域名、端口不同,需要跨域
跨域解决方案
jsonp:JSON with Padding
- script标签没有同城限制
- 服务端返回页面上callback包裹的json数据
- 兼容性好
- 仅支持GET
CORS:Cross-origin resource sharing 跨域资源共享
简单请求 :
满足以下 2 条件
- GET HEAD POST
- Content-Type
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
复杂请求:
不满足以上2条件
- 需发送 OPTION 预检请求,查询服务器支持的方法
- 按请求类别处理
const express = require('express')
const app = express()
const whiteList = ['http://localhost']
app.use((req, res, next) => {
const origin = req.headers.origin
if (whiteList.includes(origin)) {
// 允许访问源,附带凭证请求时,必须指定 URI。相反,可设置为 *
res.setHeader('Access-Control-Allow-Origin', origin)
// 允许请求头,逗号隔开
res.setHeader('Access-Control-Allow-Headers', 'authorization, username')
// 允许请求方法,逗号隔开
res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, POST, OPTIONS')
/* 允许凭证
客户端需配置 const xhr = new XMLHttpRequest()
xhr.withCredentials = true */
res.setHeader('Access-Control-Allow-Credentials', true)
// 预检请求的返回结果,允许请求头和请求方法可以被缓存多久,缓存期间不再发送预检请求,单位秒
res.setHeader('Access-Control-Allow-Max-Age', 10)
// 允许响应头
res.setHeader('Access-Control-Expose-Headers', 'authorization, username')
if (req.method === 'OPTIONS') {
res.end() // 预检请求直接返回空响应体
}
}
})
postMessage
- window属性
- 跨窗口,跨框架frame、iframe,跨域
- 允许不同源脚本采用异步方式进行有限通信
otherWindow.postMessage(message, targetOrigin, [transfer])
// otherWindow:
iframe.contentWindow 属性
window.open 返回
window.frames 访问
window.onmessage = e => console.log(e.data) // 接收返回数据
Websocket
- 基于 TCP
- 全双工通信
- 应用层协议
// 客户端
const socket = new WebSocket('ws://localhost:3000')
socket.onopen = () => socket.send('message') // 向服务器发送数据
soket.onmessage = e => console.log(e.data) // 接收服务器返回数据
// server.js
const express = require('express')
const app = express()
const ws = require('ws')
const wss = new ws.Server({port: 3000})
wss.on('connection', ws => {
ws.on('message', data => console.log(data))
})
代理服务器转发
- 代理服务器设置 CORS 请求头字段
nginx
add_header
kangle
- 回应控制,增加表,标记模块,add_header
nodejs
response.writeHead
- 代理服务器向源服务器继续请求
nginx
七层 HTTP 代理:配置 http
http {
server {
listen 80;
location / {
proxy_pass http://127.0.0.1:3000
}
}
}
- 四层 TCP 代理:配置 stream
steam {
upstream proxyServer {
server 127.0.0.1:3000;
}
server {
listen 80;
proxy_pass proxyServer;
}
}
document.domain
- 主域名相同,子域名不同
- 设置值为 主域名
iframe
- window.name
- 不超过 2MB
- 同一个iframe
- 加载跨域页,跨域页设置 window.name
- 加载同域页,读取 iframe.contentWindow.name
location.hash
- 不会被 URL 编码
- 加载跨域页,参数跟在 # 后。window.onhashchange 监听 hash 变化
- 跨域页获取 location.hash,加载同域页,参数跟在 # 后
- 同域页设置 window.parent.parent.location.hash = location.hash,将参数回传