今天在联调接口的时候,发现了一个奇怪的错误Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response
javascript
OPTIONS
请求,得到浏览器支持的请求类型,那么什么时候会进行预检请求呢?
只有在浏览器发送非简单请求的状况下,才会发送预检请求html
那么什么样叫作非简单请求,什么又是简单请求呢?前端
只要同时知足如下两大条件,就属于简单请求。java
凡是不一样时知足上面两个条件,就属于非简单请求。node
这是该问题所引出的相关名词,本着好奇的原则,继续往下走...linux
跨域是针对浏览器端而产生的,服务器端的通讯并不会产生这样的问题,这就引出了第一个解决跨域的思路----代理服务器(浏览器请求本地起的服务器—同源服务器,再由后者请求外部服务)而且跨域并不是浏览器限制了发起跨站请求,而是跨站请求能够正常发起,可是返回结果被浏览器拦截了。ios
咱们利用node能够实现代理服务器,笔者是利用了http-proxy-middlewaregit
var proxy = require('http-proxy-middleware');
var apiProxy = proxy('/api', {target: 'http://www.example.org', changeOrigin: true});
复制代码
在这里changeOrigin: true
引发了个人兴趣,思考为何会存在该项配置?这里提到了虚拟主机与独立主机的概念github
在咱们ping baidu.com的时候会获得IP地址,浏览器经过这个IP地址是能够访问网站的(独立主机),在咱们ping apple.com的时候获得的IP地址是不能经过浏览器的方式访问的(共享主机或者虚拟主机) 虚拟主机是一种在单一主机或主机群上,实现多网域服务的方法,能够运行多个网站或服务的技术,所以它能够共享服务器的内存、CPU等资源web
虚拟主机主要有如下几种类型
在http-proxy-middleware
中使用的changeOrigin
配置项正式因为使用了网址名称对应的虚拟主机。
在本篇博客中,该种方式会进行详细介绍,利用AJAX进行跨域资源共享的时候,咱们就会引出文章刚开始所遇到的问题,简单请求和非简单请求。
'use strict';
var express = require('express'),
app = express();
app.get('/auth/:id/', function (req, res) {
res.send({ id:req.params.id });
});
app.listen(3000);
复制代码
而后利用backend.js
指向一个html
文件,在html
里面发送ajax
请求,模仿跨域(端口号不一样)
'use strict';
var express = require('express'),
app = express();
app.use(express.static("./"))
app.get('/', function (req, res) {
res.render(__dirname + '/index.html');
});
app.listen(4000);
复制代码
最后是html
文件,引入了axios
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
</body>
<script type="text/javascript">
axios.get('http://localhost:3000/auth/1')
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
</script>
</html>
复制代码
当发起请求时,咱们发现
Access-Control-Allow-Origin
字段(详见下文),就知道出错了,从而抛出一个错误。 那么解决方法也很简单,在后端加上容许跨域请求。
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
复制代码
这样就能够正常访问
Content-Type
为application/json
时,代码以下:<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
</body>
<script type="text/javascript">
axios.post('http://localhost:3000/auth', {
name: 'gao'
}, {
headers: {
'Content-Type': 'application/json'
}
})
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
</script>
</html>
复制代码
会发送如图所示的预检请求:
Content-Type
为
application/x-www-form-urlencoded
时,代码以下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
</body>
<script type="text/javascript">
axios.post('http://localhost:3000/auth', {
name: 'gao'
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
</script>
</html>
复制代码
会发现,浏览器不会发送预检请求而且返回成功
后端代码以下:
'use strict';
var express = require('express'),
app = express();
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "content-type");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
app.get('/auth/:id/', function (req, res) {
res.send({ id:req.params.id });
});
app.post('/auth', function (req, res) {
res.send({ id:req.params.id });
});
app.listen(3000);
复制代码
会发现加入了这两行代码便可。
res.header("Access-Control-Allow-Headers", "content-type"); // 这里的content-type是默认的,根据客户端请求来设定
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
复制代码
此时POST会发送两次请求:
POST
请求。
像其余的技术,包括JSONP、LocalStorage、cookie、postMessage在此很少作介绍,能够参考阮大的博客进行参考。
在有些时候,后端的接口因为各类不能知足咱们所须要的跨域支持,那么就须要前端本身下功夫,咱们思考一下,既然浏览器因为安全策略阻止了返回的结果,那么就能够在浏览器的安全策略上进行修改。
设置Chrome浏览器的 disable-web-security
, 实现跨域访问后端的接口。
"C:\Users\UserName\AppData\Local\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir
open -a "Google Chrome" --args --disable-web-security --user-data-dir
chromium-browser --disable-web-security