跨域
- 不同源的Ajax请求均为跨域, 即浏览器url和请求接口地址的协议+域名+端口有一个不相同的Ajax请求
- 受浏览器的同源策略影响,浏览器会拒绝不同源的Ajax请求.
同源策略
- 是浏览器的基本安全策略,不能通过Ajax请求不同域的数据
- 同源:协议+域名+端口相同
- 解决:XSS、CSFR等攻击
为什么需要跨域请求
一个需求需要请求多个服务器的接口
跨域请求方式
1. jsonp
使用script标签进行发起get请求,因为script标签请求不受同源策影响,script标签的get请求不是Ajax请求。
- 优点: 兼容性好
- 缺点: 只能发起get请求,jsonp的错误处理机制没有XMLHttpRequst好
// 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
<script src="http://test.com/data.php?callback=dosomething"></script>
// 处理服务器返回回调函数的数据
<script type="text/javascript">
function dosomething(res){
console.log(res.data)
}
</script>
// 封装方法
function jsonp({url, params, callback}) {
jsonp.cbId = jsonp.cbId || 1
jsonp.callbacks = jsonp.callbacks || []
jsonp.callbacks[jsonp.cbId] = callback
let script = document.createElement('script')
params['callback'] = `jsonp.callbacks[${jsonp.cbId}]`
script.setAttribute('src', url + getParams(params))
document.body.append(script)
jsonp.cbId++
}
// 处理服务器返回回调函数的数据
function dosomething(res){
console.log(res.data)
}
jsonp({
url: "http://test.com/data.php?callback=dosomething",
params: {id: 1},
callback: dosomething
})
2. CORS 跨域资源共享
CORS 是W3C的一个官方方案,跨源Ajax请求的根本解决方法。
- 普通跨域实现:服务器端设置Access-Control-Allow-Origin, 如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问
// 服务器
response.setHeader("Access-Control-Allow-Origin", "http://www.main.com"); // 指定地址可以访问
response.setHeader("Access-Control-Allow-Origin", "*"); // 允许所有域访问
- 带cookie的跨域请求:前端需设置xhr.withCredentials = true,服务器端设置Access-Control-Allow-Origin
// 前端
let xhr = new XMLHttpRequest()
xhr.withCredentials = true // 前端设置是否带cookie
// 服务器
response.setHeader("Access-Control-Allow-Origin", "http://www.main.com");
response.setHeader("Access-Control-Allow-Credentials", "true");
3. postMessage
window.postMessage(mssage, targetOrigin) 是html5新引进的特性,可以用来向其他window对象发送消息,无论这个window对象属于同源或不同源。
window.postMessage(message, targetOrigin);
const openWindow = window.open('http://www.test.com', 'title')
openWindow.postMessage('the data', 'http://www.test.com')
// http://www.test.com 接受消息
window.addEventListener('message', function(e) {
console.log(e.data) // 发送的数据
console.log(e.source) // 消息发送的地址
console.log(e.origin) // 消息发向的地址
})