JS Fetch API在带Authorize属性的ASP.NET Core 2控制器中失效问题
问题根源与解决办法
你遇到的这个情况其实是浏览器预检请求和ASP.NET Core授权机制共同作用的结果,我给你拆解下:
为什么fetch请求被重定向,jQuery却正常?
- 你的fetch请求加了
Content-Type: application/json头,但这是个GET请求——GET请求本来就没有请求体,这个头完全多余,反而触发了浏览器的预检OPTIONS请求。根据浏览器的CORS规则,只要请求头不在application/x-www-form-urlencoded、multipart/form-data、text/plain这三类里,就会先发送OPTIONS请求询问服务器是否允许这个自定义头。 - 而OPTIONS请求默认不会携带身份验证Cookie,你的
MusicController加了[Authorize],所以这个OPTIONS请求直接被拦截重定向到登录页。浏览器看到OPTIONS请求被重定向,就直接终止了后续的GET请求,自然到不了控制器。 - 反观jQuery的
$.get,它发送的是标准的简单请求:没有自定义Content-Type头,不需要预检,直接带着登录后的Cookie发起请求,所以能顺利通过授权验证,到达控制器。 - 旧版ASP.NET对预检请求的处理逻辑和ASP.NET Core不一样,所以之前的代码能跑通,现在就出问题了。
解决办法(推荐第一种)
1. 去掉多余的Content-Type头(最省事)
既然是GET请求,完全不需要设置Content-Type,修改后的fetch代码如下:
fetch("/music/index") .then(response => { if (!response.ok) { throw response; } return response.json(); }) .then(json => { console.log("Done! It's all good"); }) .catch(response => console.log(response));
这样请求就变成了简单请求,不会触发预检,同域下默认会携带登录Cookie,就能正常访问控制器了。
2. 保留头的情况下适配服务器(不推荐,没必要)
如果你非要保留这个头,需要两步操作:
- 首先让fetch发送请求时携带Cookie:
fetch("/music/index", { headers: { "Content-Type": "application/json" }, credentials: 'same-origin' // 确保同域请求携带Cookie }) .then(response => { if (!response.ok) { throw response; } return response.json(); }) .then(json => { console.log("Done! It's all good"); }) .catch(response => console.log(response));
- 然后在ASP.NET Core中配置允许OPTIONS请求跳过授权验证(以.NET 6+的
Program.cs为例):
app.UseAuthorization(); // 新增这段,让OPTIONS请求直接返回200,不经过授权 app.Use(async (context, next) => { if (context.Request.Method == HttpMethod.Options.Method) { context.Response.StatusCode = StatusCodes.Status200OK; await next(); } else { await next(); } });
内容的提问来源于stack exchange,提问作者Dimitar Dimitrov
相关产品推荐
相关产品推荐

