js跨域解决方案
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对 JavaScript 实施的安全限制,那么只要协议、域名、端口有任何一个不同, 都被当作是不同的域。 跨域原理,即是通过各种方式, 避开浏览器的安全限制。
1 跨域资源共享(cors)
后台服务器端通过设置 Access-Control-Allow-Origin 即可,前端无需设置,若要带 cookie 请求,前后端都需要设置 。
res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers", "*")
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS")
res.header("Content-Type", "application/json")
2 jsonp
通过动态创建 script标签,再请求一个带参网址实现跨域通信。需要注意的是:jsonp只能实现GET请求。
2.1 原生js实现
// 参数处理
function handleParams(data) {
let url = ''
for (let key in data) {
let value = data[key] !== undefined ? data[key] : ''
url += `&${key}=${encodeURIComponent(value)}`
}
return url
}
let count = 1
// 原生jsonp实现
function originJsonp(option) {
// 1.提取url
const url = option.url
// 2.创建一个script标签以及一个不重复的callback
const script = document.createElement('script')
const callback = 'jsonp' + count++
return new Promise((resolve, reject) => {
try {
// 3.监听window上的jsonp调用,响应成功时调用该函数,并会把响应成功的数据当作参数传入
window[callback] = function(result) {
// 完成本次请求,移除script标签
document.body.removeChild(script)
resolve(result)
}
// 4.在body中添加script标签
// 处理参数
const params = handleParams(option.data)
script.src = url + '?callback=' + callback + params
document.body.appendChild(script)
} catch (e) {
document.body.removeChild(script)
reject(e)
}
})
}
const option = {
// 必须加上http
url: 'http://localhost:4000/data',
data: {
id: 123
}
}
originJsonp(option).then(res => {
// 处理响应数据
console.log(res)
}, (err) => {
console.log(err)
})
程序执行时,会动态创建一个script标签。
<script src="http://localhost:4000/data?callback=jsonp1&id=123"></script>
Request URL: http://localhost:4000/data?callback=jsonp1&id=123
2.2 jquery实现
jquery 会自动生成一个全局函数来替换 callback=? 中的问号
// 必须带上http
$.getJSON('http://localhost:4000/data?callback=?&id=123', function(jsondata) {
// 处理响应数据
console.log(jsondata)
})
Request URL: http://localhost:4000/data?callback=jQuery36009714242920403502_1625909986994&id=123&_=1625909986995
2.3 后台数据处理
app.get('/data', (req, res) => {
// 获取jsonp回调函数名称
const callback = req.query.callback
const resData = {
name: 'jack',
age: 22
}
// 判断是否为jsonp请求
if (callback) {
// 设置发送的内容类型为text/javascript
res.type('text/javascript')
res.send(`${callback}(${JSON.stringify(resData)})`)
} else {
res.send(resData)
}
})
或者
app.get('/data', (req, res) => {
const resData = {
name: 'jack',
age: 22
}
res.jsonp(resData)
})
3 document.domain
此方案仅限主域相同,子域不同的跨域应用场景。
两个页面都通过 js 强制设置 document.domain 为基础主域, 就实现了同域。
4 location.hash
a 欲与 b 跨域相互通信, 通过中间页 c 来实现。 三个页面,不同域之间利用 iframe 的 location.hash 传值,相同域之间直接 js 访问来通信。
5 window.name
通过 iframe 的 src 属性由外域转向本地域,跨域数据即由 iframe 的 window.name 从外域传递到本地域。
6 postMessage
可以跨域操作的 window 属性之一。
7 http-proxy
启一个代理服务器,实现数据的转发 。
8 nginx
通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
9 websocket
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。