前端跨域
1、概念
跨域影响:浏览器不能执行其他网站的脚本
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 JS 对象无法获取
- Ajax请求发送不出去
同源策略:浏览器对javascript添加的安全限制 同源策略是一种约定 是浏览器核心的安全功能
什么是同源:协议、域名、端口都相同
什么是跨域:不满足协议、域名、端口都相同
例如:以下链接是否与http://www.test_notice.com/index.html同源
http://www.test_notice.com/login.html同源
https://www.test_notice.com/index.html不同源(协议不同)
https://www.test_notice.com:80/index.html不同源(端口号不同)
https://www.test_not.com:80/index.html不同源(域名不同)
2、解决跨域
JSON和JSONP区别
JSON:(JavaScript Object Notation)一种轻量级的数据交互格式
JSONP:一种非正式传输协议,允许用户传递一个callback(或者一开始就定义一个回调方法)参数给服务端,然后服务端返回数据时会将这个callback 参数作为函数名来包裹住 JSON 数据,客户端就可以随意定制自己的函数来自动处理返回数据了。
大前提:web页面调用js文件不受跨域问题的影响,凡是拥有 src 这个属性的标签都拥有跨域的能力,比如img和script(就可以请求得到一个静态资源,本质上就是一个GET请求)
方式一:JSONP
和ajax没有关系,只支持 GET 请求 不支持post请求
核心:网页通过添加一个<script>标签,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
原理:
- 客户端利用 script 标签的 src 属性,去请求一个接口,因为 src 属性不受跨域影响(浏览器会把这一段字符串当做js来执行)
- 服务端响应一个字符串
- 客户端接收到字符串,然后把它当做 JS 代码运行
实现:
后端代码
app.get('api/jsonp',(req,res)={
//接收客户端的函数名
let fn = query.callback;
let obj = {name:'圆圆',age:18}
let str = JSON.stringify(obj)
res.send(fn + `(${str})`)
})
前端代码(如果test.com域名下)
// 向服务器test.com发出请求,该请求查询字符串有一个callback参数,用来指定回调函数的名字
<script src="http://test.com/api/jsonp?callback=dosomething"></script>
// 处理服务器返回回调函数的数据
<script type="text/javascript">
function dosomething(res){
// 处理获得的数据
console.log(res.data)
}
</script>
缺陷:
安全问题(请求代码中可能存在安全隐患)
要确定jsonp请求是否失败并不容易
方式一:CORS
- 前端什么也不用做
- 后端只需要开启cors(跨域资源分享(Cross-Origin Resource Sharing))
- 它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法
- 使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败
方式三:proxy(跨域请求devServer代理中的几种配置)
No.1:只修改域名
接口请求的url格式形如:/myadress/aboutUs/info.php(而不是http://localhost:8081/myadress/aboutUs/info.php)
devServer:{
proxy:{
'/myadress':{
target:'http://www.test_notice.com', // 要访问的跨域的域名
ws:true, // 是否启用websockets
changOrigin:true // 开启代理:本地会创建一个虚拟服务器,然后发送请求,并同时接收请求的数据,这样客户端和服务端进行数据交互就不会有跨域问题
}
}
}
实现:
- 代理会检查请求开头是否为/myadress,检查匹配,则走代理
- 遇到/myadress,把默认域名http://localhost:8080地址改成 target 对应的http://www.test_notice.com地址
- newwork中的Headers显示http://localhost:8080/myadress/aboutUs/info.php,真正请求的是http://www.test_notice.com/myadress/aboutUs/info.php
No.2 :有标识
接口请求的url格式形如:/api/myadress/aboutUs/info.php
devServer:{
proxy:{
'/api':{
target:'http://www.test_notice.com', // 要访问的跨域的域名
ws:true,
changOrigin:true,
pathRewrite:{
'^/api':''
}
}
}
}
实现:
- 代理会检查请求头开始是否为/api,检查匹配,则走代理
- 真实的请求中没有/api,因为在pathRewrite中把’/api’去掉(既有了标识, 又能在请求接口中把/api去掉)
- newwork中的Headers显示http://localhost:8080/myadress/aboutUs/info.php,真正请求的是http://www.test_notice.com/myadress/aboutUs/info.php
No.3:稍作省略
接口请求的url格式形如:/myadress/info.php
请求没写aboutUs,目的是跨域再加上
devServer:{
proxy:{
'/myadress':{
target:'http://www.test_notice.com', // 要访问的跨域的域名
ws:true,
changOrigin:true,
pathRewrite:{
'^/myadress/':'/myadress/aboutUs'// 注意这里aboutUs后面没有/
}
}
}
}
实现:
- 代理会检查请求头开始是否为/myadress则替换成/myadress/aboutUs
- 注意/aboutUs后边没有/
- newwork中的Headers显示http://localhost:8080/myadress/aboutUs/info.php,真正请求的是http://www.test_notice.com/myadress/aboutUs/info.php
No.4:稍作省略(同No.3)
接口请求的url格式形如:/myadress/info.php
请求没写aboutUs,目的是跨域再加上
devServer:{
proxy:{
'/myadress':{
target:'http://www.test_notice.com/myadress/aboutUs', // 要访问的跨域的域名
ws:true,
changOrigin:true,
pathRewrite:{
'^/myadress/':'/' //这里必须这样写
}
}
}
}
实现
- 代理会检查请求头开始是否为/myadress则替换成http://www.test_notice.com/myadress/aboutUs
- pathRewrite: { ‘^/myadress’: ‘/’},这里/表示使用target中的/myadress/aboutUs
- newwork中的Headers显示http://localhost:8080/myadress/aboutUs/info.php,真正请求的是http://www.test_notice.com/myadress/aboutUs/info.php