使用Jest+Supertest测试调用LOL API的Node.js接口时出现401预检错误
解决Jest+Supertest调用LOL API时的预请求401错误
兄弟,我之前在测试调用第三方API的时候也踩过这个一模一样的坑,太懂这种明明HTTPie和浏览器都正常,一到测试就炸的郁闷了!
问题根源其实很明确:预请求(OPTIONS)没带上LOL API要求的认证信息。
咱们捋清楚来龙去脉:
- HTTPie是直接发你指定的请求(比如GET),不会自动触发OPTIONS预请求;
- 浏览器发OPTIONS的时候,会自动带上你之前设置的认证头(比如
X-Riot-Token),而且你的CORS配置也允许这些头传递; - 但Supertest在模拟浏览器请求时,默认发的OPTIONS预请求不会自动继承你在GET/POST里设置的认证头,而LOL API现在要求所有请求(包括OPTIONS)都必须携带API密钥,所以就直接返回401了。
给你几个可行的解决办法,按优先级排序:
1. 让服务器转发OPTIONS请求时带上认证头
如果你的Node.js API是作为代理转发请求到LOL API的,那一定要确保**所有请求类型(包括OPTIONS)**都带上X-Riot-Token头。
比如用http-proxy-middleware的话,配置可以改成这样:
const { createProxyMiddleware } = require('http-proxy-middleware'); app.use('/lol-proxy', createProxyMiddleware({ target: 'https://na1.api.riotgames.com', changeOrigin: true, onProxyReq: (proxyReq, req, res) => { // 不管什么请求方法,都加上LOL API的密钥 proxyReq.setHeader('X-Riot-Token', process.env.LOL_API_KEY); } }));
这样不管是浏览器还是Supertest发的OPTIONS请求,经过你的服务器转发时都会带上密钥,LOL API就不会返回401了。
2. 在测试中手动处理OPTIONS预请求
如果不想改服务器配置,也可以在测试里先手动发送带认证头的OPTIONS请求,再发实际请求:
const request = require('supertest'); const app = require('../app'); test('成功获取LOL召唤师数据', async () => { const testAgent = request.agent(app); // 先发送OPTIONS请求,带上API密钥 await testAgent.options('/your-api-endpoint') .set('X-Riot-Token', process.env.LOL_API_KEY) .expect(200); // 再发送实际的GET请求 const response = await testAgent.get('/your-api-endpoint') .set('X-Riot-Token', process.env.LOL_API_KEY) .expect(200); // 这里可以加你的断言逻辑 expect(response.body).toHaveProperty('summonerName'); });
3. 调整Supertest的预请求行为
有些版本的Supertest支持关闭自动预请求,你可以试试在请求里加上preflight: false选项:
await request(app) .get('/your-api-endpoint') .set('X-Riot-Token', process.env.LOL_API_KEY) .send({ preflight: false }) .expect(200);
不过这个方法不一定适用于所有版本,优先试试前两个更稳妥。
最后再补个小提醒:检查你的CORS中间件配置,确保允许X-Riot-Token这类自定义头被传递,比如用cors包的话:
const cors = require('cors'); app.use(cors({ allowedHeaders: ['X-Riot-Token', 'Content-Type'], methods: ['GET', 'POST', 'OPTIONS'] }));
这样应该就能彻底解决这个预请求401的问题了!
内容的提问来源于stack exchange,提问作者KarimS
相关产品推荐
相关产品推荐

