React Axios调用遇连接拒绝及CORS预请求401问题求助
问题分析与解决方案
核心问题
你的问题根源在于OWIN中间件执行顺序错误,导致CORS预请求(OPTIONS)被JWT认证中间件拦截,返回401 Unauthorized。同时初始的ERR_CONNECTION_REFUSED大概率是因为React开发服务器(默认3000端口)与API服务器(10000端口)跨域,且未正确配置CORS规则。
具体解决方案
1. 调整OWIN中间件顺序(关键)
OWIN中间件按注册顺序执行,必须保证CORS处理和OPTIONS请求放行逻辑在IP过滤、JWT认证之前执行,否则预请求会被后续拦截器直接拒绝。
修改你的.NET Framework 4.8 Web API启动类代码,调整中间件顺序并优化OPTIONS处理:
public void Configuration(IAppBuilder app) { // 第一步:配置CORS规则,放在最前端 app.UseCors(new CorsOptions { PolicyProvider = new CorsPolicyProvider { PolicyResolver = context => Task.FromResult(new CorsPolicy { AllowAnyMethod = true, AllowAnyHeader = true, Origins = { "http://localhost:10000", "http://localhost:3000" }, SupportsCredentials = true }) } }); // 第二步:直接放行OPTIONS预请求,跳过后续所有中间件 app.Use(async (context, next) => { if (context.Request.Method == "OPTIONS") { context.Response.StatusCode = 200; // 显式返回CORS响应头,避免浏览器报错 context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:3000", "http://localhost:10000" }); context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Authorization", "Content-Type" }); context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "GET", "POST", "PUT", "DELETE", "OPTIONS" }); await context.Response.WriteAsync(""); return; // 终止中间件链,不进入IP过滤和JWT认证 } await next(); }); // 第三步:IP过滤中间件 var authorizedIPs = new HashSet<string> { "::1" }; foreach (var ip in Config.RestrictedAccesIps) { authorizedIPs.Add(ip); } app.Use(typeof(IpFilterMiddleware), authorizedIPs); // 第四步:JWT认证中间件 if (Config.AuthMode == WebApi.GlobalConst.Auth0) { if (string.IsNullOrEmpty(Config.OrganizationId)) { throw new ArgumentNullException("Organization Id missing"); } var domain = Config.Domain; var apiIdentifier = Config.ApiIdentifier; var keyResolver = new OpenIdConnectSigningKeyResolver(domain); app.UseJwtBearerAuthentication( new JwtBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, // 额外配置:确保非OPTIONS请求的Token校验正常 Provider = new OAuthBearerAuthenticationProvider { OnValidateIdentity = context => { // 仅对非OPTIONS请求执行身份校验 if (context.Request.Method != "OPTIONS") { // 这里可以添加自定义校验逻辑 } return Task.FromResult<object>(null); } }, TokenValidationParameters = new TokenValidationParameters() { ValidAudience = apiIdentifier, ValidateIssuer = true, ValidateIssuerSigningKey = true, ValidateLifetime = true, ValidateAudience = true, ValidIssuer = domain, IssuerSigningKeyResolver = (token, securityToken, kid, parameters) => keyResolver.GetSigningKey(kid) } }); } // 第五步:配置Web API路由 var httpConfiguration = WebApiConfig.ConfigureWebApi(); app.UseWebApi(httpConfiguration); }
2. 优化React端请求代码
添加调试日志,确认Token有效性和请求细节:
const [products, setProducts] = useState([]); const { getAccessTokenSilently } = useAuth0(); useEffect(() => { const fetchProducts = async () => { try { const accessToken = await getAccessTokenSilently(); console.log("获取到的Token:", accessToken); // 对比Postman的Token,确认受众(Audience)一致 const response = await axios.get('http://localhost:10000/******/Currencies', { headers: { Authorization: `Bearer ${accessToken}` } }); setProducts(response.data.data); } catch (error) { // 打印详细错误信息,方便排查 console.error("请求错误:", error.response?.status, error.response?.data || error.message); } }; fetchProducts(); }, [getAccessTokenSilently]);
3. 额外校验点
- 确认Postman和React请求的
URL路径完全一致(注意斜杠、路径后缀); - 检查Auth0配置的
API Identifier与Token的aud字段是否匹配,不匹配会导致JWT校验失败; - 确保API服务器的IP过滤规则包含React开发服务器的IP(本地测试可保留
::1)。
内容的提问来源于stack exchange,提问作者AnthonyDa
相关产品推荐
相关产品推荐

