使用Fetch API发送POST请求本地返回401但Postman可正常请求
问题分析与解决方案
核心问题:mode: 'no-cors'导致认证头失效
你代码里设置的mode: 'no-cors'是关键问题——在这个模式下,浏览器会强制限制请求头的发送,自定义的Authorization和Content-Type: application/json头会被忽略或替换为简单头,服务器根本收不到正确的Basic认证信息,自然返回401。另外,no-cors模式下你无法读取真实的响应内容,调试也会受阻。
Postman不受浏览器CORS政策限制,所以能正常发送所有请求头;而Postman Mock服务器本身已经配置了兼容CORS的响应头,所以本地请求能成功。
分步解决方案
1. 移除mode: 'no-cors'
首先修改fetch配置,删掉这一行,让浏览器以正常模式发送请求:
fetch("你的目标URL", { // 删掉 mode: 'no-cors' method: "POST", headers: { 'Content-Type': 'application/json', 'Authorization': 'Basic ' + btoa(encodeURIComponent(username) + ":" + encodeURIComponent(password)) }, body: JSON.stringify(data) })
注:用encodeURIComponent处理用户名/密码,避免包含特殊字符时btoa编码失败
2. 处理CORS跨域问题
移除no-cors后,浏览器会触发CORS预检请求(OPTIONS),需要确保目标服务器配置了正确的CORS响应头:
如果服务器由你控制,添加以下响应头:
Access-Control-Allow-Origin: http://127.0.0.1:5500(Live Server默认地址,或者用*允许所有来源,生产环境不推荐)Access-Control-Allow-Headers: Content-Type, Authorization(允许自定义头)Access-Control-Allow-Methods: POST, OPTIONS(允许POST和预检OPTIONS请求)
比如用Express框架时,可以用
cors中间件快速配置:const cors = require('cors'); app.use(cors({ origin: 'http://127.0.0.1:5500', allowedHeaders: ['Content-Type', 'Authorization'], methods: ['POST', 'OPTIONS'] }));如果服务器不由你控制,使用本地代理绕过跨域限制:
写一个简单的Node.js代理服务器,将本地请求转发到目标服务器:const http = require('http'); const https = require('https'); const { URL } = require('url'); const proxyServer = http.createServer((req, res) => { const targetUrl = new URL("你的目标服务器URL"); const options = { hostname: targetUrl.hostname, port: targetUrl.port || (targetUrl.protocol === 'https:' ? 443 : 80), path: targetUrl.pathname + req.url, method: req.method, headers: { ...req.headers, host: targetUrl.hostname } }; const proxyReq = (targetUrl.protocol === 'https:' ? https : http).request(options, proxyRes => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res, { end: true }); }); req.pipe(proxyReq, { end: true }); }); proxyServer.listen(3000, () => console.log('代理服务器运行在http://localhost:3000'));启动代理后,把fetch的URL改成
http://localhost:3000即可。
3. 完善请求错误处理
添加错误捕获逻辑,方便调试请求失败的原因:
fetch(...) .then(res => { if (!res.ok) { throw new Error(`请求失败:${res.status} ${res.statusText}`); } return res.json(); // 若服务器返回JSON数据 }) .then(data => console.log("请求成功:", data)) .catch(err => console.error("请求出错:", err));
修正后的完整代码
<!DOCTYPE html> <html> <head> <title>Title</title> </head> <body> <input id="name" type="text" name="name" placeholder="name"> <input type="text" id="username" name="username"> <input type="password" id="password" name="password"> <button type="submit" onclick="JSONTest()"> Submit </button> <script type="text/javascript"> const JSONTest = function() { const name = document.getElementById("name").value; const username = document.getElementById("username").value; const password = document.getElementById("password").value; const data = {title: name}; fetch("你的目标URL", { method: "POST", headers: { 'Content-Type': 'application/json', 'Authorization': 'Basic ' + btoa(encodeURIComponent(username) + ":" + encodeURIComponent(password)) }, body: JSON.stringify(data) }) .then(res => { if (!res.ok) throw new Error(`请求失败:${res.status}`); return res.json(); }) .then(data => console.log("请求成功!响应:", data)) .catch(err => console.error("请求出错:", err)); }; </script> </body> </html>
内容的提问来源于stack exchange,提问作者user17159490
相关产品推荐
相关产品推荐

