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#等服务端语言
  • 要是没有沟通加上即可
相关推荐
Mr Xu_5 分钟前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js
未来龙皇小蓝9 分钟前
RBAC前端架构-01:项目初始化
前端·架构
程序员agions17 分钟前
2026年,微前端终于“死“了
前端·状态模式
万岳科技系统开发17 分钟前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法
程序员猫哥_25 分钟前
HTML 生成网页工具推荐:从手写代码到 AI 自动生成网页的进化路径
前端·人工智能·html
龙飞0525 分钟前
Systemd -systemctl - journalctl 速查表:服务管理 + 日志排障
linux·运维·前端·chrome·systemctl·journalctl
我爱加班、、31 分钟前
Websocket能携带token过去后端吗
前端·后端·websocket
AAA阿giao31 分钟前
从零拆解一个 React + TypeScript 的 TodoList:模块化、数据流与工程实践
前端·react.js·ui·typescript·前端框架
杨超越luckly37 分钟前
HTML应用指南:利用GET请求获取中国500强企业名单,揭秘企业增长、分化与转型的新常态
前端·数据库·html·可视化·中国500强
hedley(●'◡'●)1 小时前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机