Node.js中Axios POST请求报405 Method Not Allowed错误如何解决?
问题根因
返回405状态码的核心原因是浏览器发送multipart/form-data类型的非简单POST请求前,会自动发起OPTIONS方法的CORS预检请求,你的服务端只注册了POST /images路由,没有对OPTIONS请求做响应处理,预检阶段直接被拦截返回405,真正的POST请求根本不会发出。
Postman不会触发浏览器的CORS预检逻辑,所以可以直接调通接口。
现有代码还存在两个会导致请求失败的隐藏问题:
- 已经全局注册了
cors中间件,又在单个POST路由里重复手写CORS响应头,属于冗余配置,且手动配置的头不全,没有放行文件上传需要的相关请求头 - 前端手动给FormData请求设置
Content-Type: multipart/form-data,会覆盖Axios自动生成的boundary边界参数,导致后端multer中间件无法正确解析上传的文件
修复步骤
1. 修正服务端CORS配置,放行OPTIONS预检请求
删除路由内重复手写的CORS响应头代码,补全全局cors配置,单独处理所有OPTIONS预检请求,修改后的服务端代码如下:
var cors = require("cors"); var serveStatic = require('serve-static'); const path = require('path'); // 全局配置cors,无需在单个路由中重复设置响应头 app.use(cors({ origin: "*", methods: ["GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE"], allowedHeaders: ["X-Requested-With", "Content-Type", "Content-Disposition"], credentials: false })); // 统一拦截所有OPTIONS请求,返回204状态码通过预检 app.options("/*", (req, res) => { res.sendStatus(204); }); const client = new vision.ImageAnnotatorClient(config, clientOptions); // 简化POST路由,移除冗余的CORS头设置代码 app.post("/images", upload.single("file"), function (req, res, next) { client .textDetection(req.file.path) .then((results) => { res.send(results); }) .catch((err) => { res.status(400).send(err); }); }); app.use(serveStatic(path.join(__dirname, "public"))); const server = app.listen(port); console.log(`${pjson.name} running => port ${server.address().port}`);
2. 修正前端Axios请求配置
不要手动给FormData类型的请求设置Content-Type头,让Axios自动识别FormData格式并生成带正确boundary边界的请求头,同时增加空文件校验,修改后的前端代码如下:
<form role="form" class="form" onsubmit="return false;"> <div class="form-group"> <label for="file">File</label> <input id="file" type="file" class="form-control" accept=".JPG,.jpg,.jpeg,.gif,.png" /> </div> <button id="text_detect" type="button" class="btn btn-primary"> Get Text </button> </form> <script> document.getElementById('text_detect').onclick = function () { output.innerHTML = ''; const fileInput = document.getElementById('file'); if (!fileInput.files[0]) { alert('请先选择要上传的图片'); return; } const data = new FormData(); data.append('file', fileInput.files[0]); // 移除手动设置的Content-Type头,由Axios自动生成 axios.post('/images', data) .then(function (result) { const properties = result.data[0].fullTextAnnotation; console.log(properties); }) .catch(function (err) { console.log(err); }) } </script>
验证方式
修改完成后重启Node服务,打开浏览器控制台网络面板,可以看到先发起了一个状态码为204的OPTIONS请求到/images路径,预检通过后才会发送真正的POST上传请求,接口即可正常返回识别结果。
内容的提问来源于stack exchange,提问作者kate moss
相关产品推荐
相关产品推荐

