axios请求搭配onUploadProgress会多发一个OPTIONS跨域资源问题(VsCode的Live Server举例)

场景描述解释:

  • 有一个上传请求,使用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#等服务端语言
  • 要是没有沟通加上即可
相关推荐
y先森4 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy4 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189114 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
向阳12185 小时前
Dubbo HTTP接入之triple协议
网络协议·http·dubbo
IT女孩儿5 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡6 小时前
commitlint校验git提交信息
前端
虾球xz6 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇6 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒6 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员7 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js