本文主要适合前端零基础小白者,助您快速就业上手,高手勿喷。
Q:为什么会出现跨域问题?
A:出于浏览器的同源策略限制,浏览器会拒绝跨域请求(为了安全,拒绝别有用心的人盗取别人的资源,例如:Css,修改人家的文件等)
注:严格意义上来讲,浏览器不是拒绝所有的夸域请求,夸域是独属于浏览器的行为。
同源策略按以下执行:
1.浏览器允许写操作:a标签的href,meta标签的url属性,js中的location.href
2.浏览器资源嵌入:script/img等带src的标签
3.浏览器不允许读操作:*
tips:服务器与服务器之间通信不会夸域
如何实现夸域?(通常以下三种:JSONP,CORS,PostMessage,代理webpack) 常规方式
Webpack代理
原理:页面A请求页面A所在的服务器B(此时不夸域), 服务器B请求服务器C(此时不夸域)
我们一般情况下使用的cli项目其实就是启动了一个webpack的服务器,里面有一个可配置属性叫做devServer.proxy可进行代理配置
前端页面:127.0.0.1:8080 -->请求
后端服务:127.0.0.1:3000(或则136.168.2.72) -->此时跨域
devServer:{
'/api':{
target:'http://127.0.0.1:3000', //需要实际请求的地址
changeOrigin:true, //允许target参数是域名
pathRewrite:{ //路径重新
'^/api':''
},
secure:false //当运行HTTPS时,是否检查安全
}
}
请求127.0.0.1:3000/api/store/get设置后会变为:127.0.0.1:3000/store/get
Jsonp
Jsonp实现原理:通过script的src请求服务器,服务器返回一段带数据的字符串,浏览器当成js解析,全局中已有callback函数,相当于调用callback函数获得数据
//index.html
<script>
function callbackFn(res) {
console.log('res---->', res);
}
</script>
<script src="http://localhost:3000?reqName=callbackFn"></script>
// nodejs
const http = require('http'); //http模块
const url = require('url'); //解析url
const app = http.createServer((req, res) => {
let param = url.parse(req.url, true); //解析 http//:127.0.0.1?callback=callback
let data = JSON.stringify({ name: 'phenix' }); //需要返回前端的数据
//1.判断是否有reqName字段
//2.获取reqName的值(前端接收数据时的方法名callbackFn)
//3.返回前端字符串callbackFn({name:phenix}),当成js解析
if (param.query && param.query.reqName) {
const str = param.query.reqName + '(' + JSON.stringify(data) + ')';
res.end(str);//值是 callbackFn({name:phenix})
} else {
res.end();
}
});
app.listen(3000, () => {
console.log(' serve is running at 3000 port ');
});
[Jsonp的优缺点]:
优点:兼容性好
缺点:1.只支持GET请求 2.XMLHttpRequest相对于JSONP有着更好的错误处理机制
CORS
cors是w3c推荐的一种新的官方方案,能使服务器支持XMLHttpRequest的跨域请求。只需要增加一些Http请求头,让服务器能声明允许的访问来源。请求类型又分为简单请求和异步请求,异步请求会多发一次预检请求Options
简单请求
1.get
2.head
3.post(仅当post方法的content-type属于下列值之一才算简单请求)
text/plain
multipart/form-data
application/x-www-form-urlencoded
非简单请求:人为设置了以下请求头之一
Accept
Accept-Language
Content-Language
Content-Type(
不包含
text/plain
multipart/form-data
application/x-www-form-urlencoded
)
DPR
Downlink
Save-Data
ViewPort-Width
Width
非简单请求会先触发一次叫options的预检请求,询问服务器是否允许访问,服务器若允许才会继续触发请求访问数据
options请求的请求头:
Access-Control-Request-Method: POST //请求服务器的方式
Access-Control-Request-Headers: X-PINGOTHER
options请求的响应头:
> Access-Control-Allow-Origin: (https://www.baidu.com)//标识可接受的跨域请求源;
> Access-Control-Allow-Methods: POST, GET, OPTIONS //标识可接受的跨域请求方法,如GET、POST、OPTIONS;
> Access-Control-Allow-Headers: X-PINGOTHER, Content-Type //标识可接受的跨域请求自定义头;
> Access-Control-Allow-Headers:指明了实际请求中允许携带的首部字段
> Access-Control-Allow-Credentials:true //表示是否可以携带cookie
> Access-Control-Max-Age: 86400。 //标识本次预请求的有效时间(秒),期间内无需再发送预请求;请求过一次后,有效时间内不需再次请求options
> Access-Control-Expose-Headers:服务器设置的可访问的header(跨域时,浏览器只能访问Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma等常规请求头,其他自定义请求头,需要后端设置该属性,浏览器才能访问,例:x-pagination-count)