为何使用fetch发送POST请求时,Content-Type始终为text/plain而非application/json?
嘿,这个问题我之前踩过坑,核心原因其实就在你设置的mode: 'no-cors'上!
当你把fetch的请求模式设为no-cors时,浏览器会进入受限的跨域请求模式——这种模式下,你自定义的很多请求头都会被浏览器直接忽略,其中就包括你设置的Content-Type: application/json。浏览器会自动把Content-Type降级为text/plain,这是no-cors模式允许的少数几种Content-Type之一(另外两种是application/x-www-form-urlencoded和multipart/form-data)。
而你的Express服务器应该是用了express.json()(或者旧版的body-parser.json())中间件,这个中间件的作用就是专门解析Content-Type为application/json的请求体。当请求的Content-Type变成text/plain时,中间件就不会处理这个请求体,自然request.body就一直是空对象{}了。
解决办法
首选方案:移除
mode: 'no-cors'
只要你的Express服务器配置了CORS支持,就完全不需要设置no-cors模式。移除这个配置后,浏览器会正常发送你设置的Content-Type: application/json请求头,服务器的express.json()中间件就能正确解析请求体了。给你个服务器端配置CORS的简单例子:
const express = require('express'); const cors = require('cors'); const app = express(); // 启用CORS,允许跨域请求 app.use(cors()); // 解析JSON格式的请求体 app.use(express.json()); // 你的患者注册路由 app.post('/register/paitent', (req, res) => { console.log(req.body); // 现在就能拿到正确的name和password了 // 后续的注册逻辑... });如果特殊情况必须用no-cors(非常不推荐)
这种情况下,你只能用浏览器允许的Content-Type,比如text/plain,然后在服务器端手动读取并解析请求体:
客户端代码修改:var data = { name: this.state.name, password: this.state.password } fetch('http://localhost:3001/register/paitent', { method: 'POST', body: JSON.stringify(data), mode: 'no-cors', headers: new Headers({ 'Content-Type': 'text/plain' }) // 改成浏览器允许的类型 })服务器端手动解析请求体:
app.post('/register/paitent', (req, res) => { let rawBody = ''; // 逐段读取请求体 req.on('data', chunk => { rawBody += chunk.toString(); }); // 读取完成后解析JSON req.on('end', () => { try { const parsedData = JSON.parse(rawBody); console.log(parsedData); // 这里就能拿到解析后的用户数据了 } catch (err) { console.error('解析请求体失败:', err); } }); });
内容的提问来源于stack exchange,提问作者Bing Lan

