当一个请求url的协议
、域名
、端口
三者之间的任意一个
与当前页面url不同
即为跨域
。
跨域资源共享(CORS)是一种机制,它使用额外的http头告诉浏览器让运行在一个origin上的web应用被准许访问来自不同资源服务器上的指定资源
CORS不是一种错误,而是为了保护用户的一种安全机制
为什么会出现跨域问题?
XmlHttpRequest同源策略:禁止不同源的AJAX请求,主要防止CSRF攻击
CORS 请求失败会产生错误,但是为了安全,在 JavaScript 代码层面无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。
同源策略:
是浏览器的一种核心最基本的安全策略。他对来自于不同源的文档或脚本对当前文档的读写做出了限制。
同源即协议相同、域名相同、端口相同
与跨域有关的协议头
Access-Contorl-Allow-Origin
Access-Control-Allow-Origin: <origin> | *
Access-Control-Allow-Origin
参数指定了单一的源,告诉浏览器允许该源访问资源。或者,对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符“*
”,表示允许来自任意源的请求。
例如,为了允许来自 https://mozilla.org
的代码访问资源,你可以指定:
Access-Control-Allow-Origin: https://mozilla.org
Vary: Origin
如果服务端指定了具体的单个源(作为允许列表的一部分,可能会根据请求的来源而动态改变)而非通配符“*
”,那么响应标头中的 Vary字段的值必须包含 Origin
。这将告诉客户端:服务器对不同的 Origin返回不同的内容。
Access-Control-Expose-Header
在跨源访问时,XMLHttpRequest
对象的 getResponseHeader() 方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。
该头将指定标头放入允许列表中,供浏览器的 JavaScript 代码(如 getResponseHeader())获取。
Access-Control-Expose-Headers: <header-name>[, <header-name>]*
解决方法:
通过jsonp解决跨域
原生使用方法:
1.yarn add jsonp --save
2.import JsonP from 'jsonp'
3.JsonP('url',{},function(err, data){
console.log(data)
})
要是在react中使用可以先进行封装在使用
import JsonP from 'jsonp'
export default class Axios {
static jsonp(options){
return new Promise((resolve,reject)=>{
JsonP(options.url,{
param:'callback'
},function(err,res){
if(res.status === 'success') {
resolve(res)
} else {
reject(err)
}
})
})
}
}
引用:
import Axios from '../../axios/index' // 封装的文件路径
Axios.jsonp({url:'path'}).then((res)=>{
console.log(res)
}).catch((err)=>{
console.log(err)
})
用于安全请求的CORS
如果一个请求是跨域的,浏览器始终会向其添加 Origin
header。
例如,如果我们从 https://javascript.info/page
请求 https://anywhere.com/request
,请求的 header 将如下所示:
GET /request
Host: anywhere.com
Origin: https://javascript.info
正如你所看到的,Origin
包含了确切的源(domain/protocol/port),没有路径(path)。
服务器可以检查 Origin
,如果同意接受这样的请求,就会在响应中添加一个特殊的 header Access-Control-Allow-Origin
。该 header 包含了允许的源(在我们的示例中是
),或者一个星号 https://javascript.info
*
。然后响应成功,否则报错。
浏览器在这里扮演受被信任的中间人的角色:
- 它确保发送的跨源请求带有正确的
Origin
。 - 它检查响应中的许可
Access-Control-Allow-Origin
,如果存在,则允许 JavaScript 访问响应,否则将失败并报错。
这是一个带有服务器许可的响应示例:
200 OK
Content-Type:text/html; charset=UTF-8
Access-Control-Allow-Origin: https://javascript.info
服务端代理(Nginx代理)
#如果监听到请求接口地址是 www.xxx.com/api/page ,nginx就向http://www.yyy.com:9999/api/page这个地址发送请求
server {
listen 80;
server_name www.xxx.com;
#判过滤出含有api的请求
location /api/ {
proxy_pass http://www.yyy.com:9999; #真实服务器的地址
}
}
前端解决方法:
在react中可以在package.json中添加
假设请求地址为:http://xxxx/api/data
"proxy":"http://xxxx"
然后在axios中更改请求地址:
/api/data
最后就可以重启项目,测试是否解决跨域