九种跨域解决方案
大约 3 分钟约 1017 字
九种跨域解决方案
1.jsonp
客户端
function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
window[callback] = function (data) {
resolve(data)
document.body.removeChild(script)
}
params = { ...params, callback } // wd=b&callback=show
let arrs = []
for (let key in params) {
arrs.push(`${key}=${params[key]}`)
}
script.src = `${url}?${arrs.join('&')}`
document.body.appendChild(script)
})
}
jsonp({
url: 'http://localhost:3000/say',
params: { wd: 'Iloveyou' },
callback: 'show'
}).then(data => {
console.log(data)
})
服务端
let express = require('express')
let app = express()
app.get('/say', function (req, res) {
let { wd, callback } = req.query
console.log(wd)
console.log(callback)
res.end(`${callback}('我不爱你')`)
})
app.listen(3000)
2.cors
客户端
let xhr = new XMLHttpRequest()
document.cookie = 'name=xiamen' // cookie不能跨域
xhr.withCredentials = true // 前端设置是否带cookie
xhr.open('PUT', 'http://localhost:4000/getData', true)
xhr.setRequestHeader('name', 'xiamen')
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response)
console.log(xhr.getResponseHeader('name'))
}
}
}
xhr.send()
服务端
let express = require('express')
let app = express()
let whitList = ['http://localhost:3000'] //设置白名单
app.use(function (req, res, next) {
let origin = req.headers.origin
if (whitList.includes(origin)) {
// 设置哪个源可以访问我
res.setHeader('Access-Control-Allow-Origin', origin)
// 允许携带哪个头访问我
res.setHeader('Access-Control-Allow-Headers', 'name')
// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 允许携带cookie
res.setHeader('Access-Control-Allow-Credentials', true)
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// 允许返回的头
res.setHeader('Access-Control-Expose-Headers', 'name')
if (req.method === 'OPTIONS') {
res.end() // OPTIONS请求不做任何处理
}
}
next()
})
app.put('/getData', function (req, res) {
console.log(req.headers)
res.setHeader('name', 'jw')
res.end('我不爱你')
})
app.get('/getData', function (req, res) {
console.log(req.headers)
res.end('我不爱你')
})
app.use(express.static(__dirname))
app.listen(4000)
3.postMessage
客户端
<iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe>
<script>
function load() {
let frame = document.getElementById('frame');
frame.contentWindow.postMessage('我爱你','http://localhost:4000');
window.onmessage = function (e) {
console.log(e.data);
}
}
window.onmessage = function (e) {
console.log(e.data);
e.source.postMessage('我不爱你',e.origin)
}
</script>
服务端
let express = require('express')
let app = express()
app.use(express.static(__dirname))
app.listen(4000)
4.name
客户端
a和b是同域的 http://localhost:3000 c是独立的 http://localhost:4000 a获取c的数据
a先引用c c把值放到window.name,把a引用的地址改到b
<iframe
src="http://localhost:4000/c.html"
frameborder="0"
onload="load()"
id="iframe"
></iframe>
<script>
let first = true
function load() {
if (first) {
let iframe = document.getElementById('iframe')
iframe.src = 'http://localhost:3000/b.html'
first = false
} else {
console.log(iframe.contentWindow.name)
}
}
</script>
服务端
let express = require('express')
let app = express()
app.use(express.static(__dirname))
app.listen(3000)
5.hash
<!-- 路径后面的hash值可以用来通信 -->
<!-- 目的a想访问c -->
<!-- a给c传一个hash值 c收到hash值后 c把hash值传递给b b将结果放到a的hash值中-->
<iframe src="http://localhost:4000/c.html#iloveyou"></iframe>
<script>
window.onhashchange = function () {
console.log(location.hash)
}
console.log(location.hash)
let iframe = document.createElement('iframe')
iframe.src = 'http://localhost:3000/b.html#idontloveyou'
document.body.appendChild(iframe)
</script>
6.domain
<!-- 域名 一级域名二级域名 -->
<!-- www.baidu.com -->
<!-- viode.baidu.com -->
<!-- a是通过 http://a.zf1.cn:3000/a.html -->
helloa
<iframe
src="http://b.zf1.cn:3000/b.html"
frameborder="0"
onload="load()"
id="frame"
></iframe>
<script>
document.domain = 'zf1.cn'
var a = 100
function load() {
console.log(frame.contentWindow.a)
}
</script>
7.websocket
客户端
// 高级api 不兼容 socket.io(一般使用它)
let socket = new WebSocket('ws://localhost:3000')
socket.onopen = function () {
socket.send('我爱你')
}
socket.onmessage = function (e) {
console.log(e.data)
}
服务端
let express = require('express')
let app = express()
let WebSocket = require('ws')
let wss = new WebSocket.Server({ port: 3000 })
wss.on('connection', function (ws) {
ws.on('message', function (data) {
console.log(data)
ws.send('我不爱你')
})
})
8.nginx
客户端
var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();
服务端
var http = require('http')
var server = http.createServer()
var qs = require('querystring')
server.on('request', function (req, res) {
var params = qs.parse(req.url.substring(2))
// 向前台写cookie
res.writeHead(200, {
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取
})
res.write(JSON.stringify(params))
res.end()
})
server.listen('8080')
console.log('Server is running at port 8080...')
9.node 中间件代理
客户端
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$.ajax({
url: 'http://localhost:3000',
type: 'post',
data: { name: 'xiamen', password: '123456' },
contentType: 'application/json;charset=utf-8',
success: function(result) {
console.log('result', result)
},
error: function(msg) {
console.log(msg)
}
})
</script>
服务端
const http = require('http')
// 第一步:接受客户端请求
const server = http.createServer((request, response) => {
// 代理服务器,直接和浏览器直接交互,需要设置CORS 的首部字段
response.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': 'Content-Type'
})
// 第二步:将请求转发给服务器
const proxyRequest = http
.request(
{
host: '127.0.0.1',
port: 4000,
url: '/',
method: request.method,
headers: request.headers
},
serverResponse => {
// 第三步:收到服务器的响应
var body = ''
serverResponse.on('data', chunk => {
body += chunk
})
serverResponse.on('end', () => {
console.log('The data is ' + body)
// 第四步:将响应结果转发给浏览器
response.end(body)
})
}
)
.end()
})
server.listen(3000, () => {
console.log('The proxyServer is running at http://localhost:3000')
})