如何模拟会话过期触发的CORS预请求拦截错误并处理?
我需要在本地环境模拟一个被CORS策略拦截的XMLHttpRequest请求,触发的错误信息如下:
Access to XMLHttpRequest at 'my http request url' (redirected from 'my web request url') from origin 'web origin' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request。
这个错误只会在非localhost环境、会话过期后调用后端API时出现,我不负责会话管理系统,不需要修复这个错误,只是想模拟它来完善错误处理逻辑,通过模态框给用户展示提示。但这个错误和常规的HttpErrorResponse不一样,我没法正确获取错误信息,也没法在对应环境调试错误处理代码。目前我的错误处理代码是这样的:
protected handleError(error: any) { let errMsg = ""; if (error.status == 0) { window.location.reload(); } else { if (error.status < 100 || error.status > 599) { errMsg = error.message; } else { if (error.error.message != undefined) { errMsg = error.error.message; } else { if (error.status) { errMsg = error.status + " - " + error.statusText; } else { errMsg = "Server Error."; } } } } return throwError(errMsg); }
要模拟这种特殊的CORS预请求重定向错误,有两个实用的方法可以试试:一个是直接在前端构造错误对象快速测试,另一个是搭个极简的本地服务器来真实触发错误。
方法1:前端直接构造错误对象(最快)
不需要额外搭建服务,直接造一个和真实错误结构一致的对象,传入你的handleError函数就能测试:
// 模拟目标CORS错误的对象,把message换成你实际收到的内容 const mockCorsRedirectError = { status: 0, message: "Access to XMLHttpRequest at 'http://example.com/api' (redirected from 'http://your-app.com') from origin 'http://your-app.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.", name: "HttpErrorResponse" }; // 直接调用handleError测试你的逻辑 yourService.handleError(mockCorsRedirectError).subscribe({ error: (errMsg) => { // 这里可以测试模态框展示逻辑 console.log(errMsg); // 比如调用你的模态框组件:showModal(errMsg); } });
另外,你当前的handleError函数在status == 0时直接刷新页面,但这个CORS错误的status也是0,所以得区分开是网络错误还是CORS预请求错误,修改一下代码:
protected handleError(error: any) { let errMsg = ""; if (error.status == 0) { // 通过错误信息里的关键词判断是不是目标CORS错误 if (error.message.includes("Redirect is not allowed for a preflight request")) { errMsg = "会话已过期,请重新登录"; // 换成你想展示给用户的提示文本 // 这里调用模态框展示提示,而不是刷新页面 // showModal(errMsg); } else { // 处理其他status=0的情况,比如网络断开 window.location.reload(); } } else { if (error.status < 100 || error.status > 599) { errMsg = error.message; } else { if (error.error?.message != undefined) { errMsg = error.error.message; } else { if (error.status) { errMsg = `${error.status} - ${error.statusText}`; } else { errMsg = "Server Error."; } } } } return throwError(() => errMsg); }
方法2:本地搭测试服务器真实触发错误
如果你想更贴近真实请求场景,可以用Node.js快速搭个简单服务器:
- 创建
server.js文件:
const http = require('http'); const server = http.createServer((req, res) => { // 处理OPTIONS预请求,返回302重定向(不添加CORS允许头) if (req.method === 'OPTIONS') { res.writeHead(302, { 'Location': 'http://example.com/login' // 注意:这里绝对不能加Access-Control-Allow-Origin等CORS相关头 }); res.end(); return; } // 普通请求也返回重定向 res.writeHead(302, { 'Location': 'http://example.com/login' }); res.end(); }); server.listen(3000, () => { console.log('测试服务器运行在http://localhost:3000'); });
运行服务器:
node server.js在你的前端代码里调用这个测试接口:
this.http.get('http://localhost:3000/api').subscribe({ error: (err) => { // 这里会真实触发你要模拟的CORS错误,传入handleError处理即可 this.handleError(err); } });
这样就能在本地环境真实复现目标错误,测试你的错误处理逻辑了。
内容的提问来源于stack exchange,提问作者M. Sgarbossa

