同源策略
同源
- 同协议
- 同域名
- 同端口
当页面上有ajax请求时,浏览器比较当前ajax请求和当前页面的url,接口,协议,域名,端口 是否完全一致,如果不一致,浏览器会拒绝掉.
那么为啥要同源呢?
为了保护知识产权,不然你做的接口别人网站都随便用了
拒绝是服务器拒绝还是浏览器拒绝呢
是浏览器拒绝的
如果跨域请求第三方接口,或者把自己的接口提供给第三方,要如何做呢?
一般有三种方法,哪三种方法呢???是下面三种方法:
- JSONP
- CORS
- 服务器中转
就这三种
JSONP
原理
- 同源策略只限制ajax请求,不限制script标签加载js.可以同script标签请求加载资源,并提前写好接收函数.
function handleData(data){
console.log(data)
}
</script>
<script src='http://xxx.xxx.com/xxx?callback=handleData'>//把callback=handleData发给服务器,服务器拿到handleData
- 服务器接到请求后,从callback参数获得
handleData
,然后把原始数据处理后变成handleData({a: 1})
- 服务器返回
handleData({a: 1})
后等于执行这个函数,因为handleData函数已经设定过
举例
- 先用nodejs写个服务器,让那个服务器在接到请求后返回fn(data)
const http = require('http')
const url = require('url')
http.createServer((req,res) =>{
let urlObj = url.parse(req.url,true)
if(urlObj.pathname === '/getWeather'){
let data = {weather: '晴',city: '杭州'}
res.end(`${urlObj.query.callback}(${JSON.stringify(data)})`)//callback就是=后面的fn,因此服务器返回fn(data),浏览器接收到后就会根据预置的方法运行
}else{
res.writeHead(404,'not fond')
res.end('not fond')
}
}).listen(8888)//端口8888,终端node一下打开服务器
- 浏览器html页面这么写
<script>
function fn(data){
document.querySelector('p').innerText = data.weather
}
</script>
//发送请求,callback里的fn传给服务器,服务器拿到再返回给浏览器fn(),浏览器然后执行
<script src='http://127.0.0.1:8888/getWeather?callback=fn'></script>
如果遇到多个请求太麻烦,可以封装一下
function jsonp(url,data={}){//确定形参为url和服务器传送内容data,默认为空对象{}
//使用promise,先获得data数据,再执行函数
return new Promise((resolve,reject) =>{
window.fn = data => resolve(data)//1.函数要绑定要全局上 2.之后设置then()中怎么执行data 3.当调用这个全局函数fn时,resolve出data给被人用
let script = document.createElement('script')//创建script的标签
let query = Object.entries(data).map(a=>`${a[0]}=${a[1]}`).join('&')
script.src = url+'?callback=fn&'+query//在script标签上添加链接
script.onerror = () =>reject('加载失败')
document.head.appendChild(script)//添加script标签
document.head.removeChild(script)//删除script标签
})
}
CORS
原理
- 发送Ajax请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin。后台收到请求后,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin;浏览器判断该响应头中是否包含当前Origin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果没有浏览器直接驳回。
- 一般都是些公开的api可以
前端需要做什么
- 什么都不需要做
服务端需要做什么
- 加一个Access-Control-Allow-Origin响应头
res.setHeader('Access-Control-Allow-Origin','*')
服务器说:“浏览器兄弟,我允许任何域都能获取资源,你不用替我拦截非同源的请求了了”
JSONP和CORS都需要服务器配合,如果不配合怎么办
这时候就用到服务器中转
服务器中转
- 发给我服务器
- 我的服务器再发给目标服务器
- 目标服务器返回我的服务器
- 我的服务器再返回