场景描述解释:
- 有一个上传请求,使用axios直接发送一个post上传请求
- 若是搭配了axios的第三个参数config的onUploadProgress后
- 就会多发一个OPTIONS请求
- 此多出来的请求,用于检查请求的方法、请求头信息等是否被目标服务器接受
- 如下图示,一个上传,两次请求
可以理解为,浏览器会发个预检查(preflight)请求到服务器进行验证,比如验证跨域。
若服务端不处理,则会报错
- 笔者的后端是express框架
- 不做处理时,是这样的报错
- 报错截图如下:
Network
Console
代码如下
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>002</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<style>
#progress-bar {
width: 300px;
height: 20px;
border: 1px solid #ccc;
background-color: #f1f1f1;
margin-bottom: 10px;
}
#progress {
width: 0;
height: 100%;
background-color: #4caf50;
}
</style>
</head>
<body>
<input type="file" />
<div id="progress-bar">
<div id="progress"></div>
</div>
<script>
let ipt = document.querySelector('input')
ipt.addEventListener('change', async (e) => {
let file = e.target.files[0]
const formData = new FormData()
formData.append('find_a_file_size_bigger_2m', file)
await uploadFn(formData)
e.target.value = null
})
let config = {
onUploadProgress: function (progressEvent) {
var progress = document.getElementById('progress');
var percent = Math.round((progressEvent.loaded / progressEvent.total) * 100);
progress.style.width = percent + '%';
console.log('percent', percent);
}
};
const uploadFn = (params) => {
return new Promise((resolve, reject) => {
axios.post('http://ashuai.work/api/simulateUpload', params, config) // 发两次请求,还有一个是options
// axios.post('http://ashuai.work/api/simulateUpload', params) // 只发送一个请求
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err)
console.log(err);
});
})
}
</script>
</body>
</html>
注意,因为是使用VsCode中使用Live Server启动这个html
所以ip端口默认是http://127.0.0.1:5500/xxx.html
这种情况下,就算直接配置相应头,也没用了
就真的得使用Cors控制了
比如,如下的后端代码:
js
// 模拟文件上传接口
route.post('/simulateUpload', function (req, res) {
res.header('Access-Control-Allow-Origin', '*'); // vscode本地是没用的
let apiRes = {
code: 0,
done: "yes",
data: "上传数据成功"
}
res.send(apiRes)
});
解决方案:使用cors配置下
npm i cors
js
const cors = require('cors');
......
app.use(cors()); // express实例服务使用cors
- 这样所有的都允许跨域了,都放行
- 当然也可以指定单独的本机的
js
app.use(cors({
origin: 'http://127.0.0.1:5500',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 注意,这里的OPTIONS请求方法
allowedHeaders: ['Content-Type', 'Authorization'], // 允许自定义请求头
}));
问:为什么会出现OPTION请求,作用是啥?
答:OPTION请求是浏览器自带的专门用于查询问一问咨询的
浏览器的OPTION说:能发请求呗?
服务器说,能,才会让后续的请求正常发起
问:大概什么情况下,会出现OPTION请求
答:
- 跨域请求
- 代码中加了自定义请求头
- POST请求的Content-Type值不属于application/x-www-form-urlencoded, multipart/form-data, 或 text/plain中的任何一种
- 正常来说,后端代码框架都会提前处理好这个问题,无论是nodejs还是java亦或是C#等服务端语言
- 要是没有沟通加上即可