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#等服务端语言
  • 要是没有沟通加上即可
相关推荐
来恩100312 分钟前
jQuery选择器
前端·javascript·jquery
前端繁华如梦14 分钟前
树上挂苹果还是挂玻璃球?Three.js 程序化果实的完整实现指南
前端·javascript
墨痕诉清风21 分钟前
Web浏览器客户端检测网站网络健康(代码)
前端·网络·测试工具
IMPYLH23 分钟前
Linux 的 wc 命令
linux·运维·服务器·前端·bash
happybasic40 分钟前
Python库升级标准流程~
linux·前端·python
川冰ICE1 小时前
前端工程化深度实战:从Webpack5到Vite5的构建工具演进与选型决策
前端
CDwenhuohuo1 小时前
优惠券组件直接用 uview plus
前端·javascript·vue.js
用户74090472362751 小时前
我用 curl 排查了一次 OpenAI-compatible API 连接失败:401、403、404 分别怎么定位
前端
kft13141 小时前
XSS深度剖析:从弹窗到持久化窃取Cookie
前端·web安全·xss·安全测试
烬羽1 小时前
《前端三权分立:HTML、CSS、JS为什么不能“乱搞”》
前端