You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于http-proxy-middleware的代理添加认证令牌报错求助

解决http-proxy-middleware设置请求头时的ERR_HTTP_HEADERS_SENT错误

嘿,我刚好碰到过一模一样的问题!你遇到的Error [ERR_HTTP_HEADERS_SENT]本质是异步操作的时机没踩对——你用的request是异步回调风格的,当你在回调里去设置proxyReq的请求头时,http-proxy-middleware早已经把请求转发给目标的/rest-api了,此时请求头已经发送给对方服务器,自然没法再修改,就抛出了这个错误。

核心解决方案:把异步请求改成同步等待

http-proxy-middleware支持异步的onProxyReq函数,只要我们把它改成async函数,然后等待获取token的操作完成后,再继续设置请求头、转发请求就行。这里推荐用Promise风格的请求库(比如axios),或者把request包装成Promise,避免回调嵌套的问题。

方案1:用axios实现(更简洁)

首先安装axios:

npm install axios

然后修改你的代理配置:

const axios = require('axios');

// 你的代理配置
const myProxy = createProxyMiddleware('/my-proxy/', {
  target: 'http://your-rest-api-domain', // 替换成你的rest-api实际域名
  changeOrigin: true,
  pathRewrite: { '^/my-proxy/': '/rest-api/' },
  onProxyReq: async function (proxyReq, req, res) {
    // 检查请求头是否已有auth-token
    if (!req.header("auth-token")) {
      try {
        // 等待认证请求完成,拿到token
        const authResponse = await axios.post('/rest-api/auth', {
          username: "user",
          password: "pass"
        });
        // 此时再设置请求头,不会触发错误
        proxyReq.setHeader("auth-token", authResponse.data.token);
      } catch (error) {
        // 处理认证失败的情况,比如返回错误给客户端
        console.error('获取token失败:', error);
        res.status(500).send('Failed to obtain authentication token');
        // 终止后续代理流程
        return;
      }
    }
  }
});

方案2:继续用request(包装成Promise)

如果你不想换库,可以用Node.js的util.promisifyrequest转成Promise风格:

const request = require('request');
const { promisify } = require('util');
const requestPromise = promisify(request);

// 你的代理配置
const myProxy = createProxyMiddleware('/my-proxy/', {
  target: 'http://your-rest-api-domain',
  changeOrigin: true,
  pathRewrite: { '^/my-proxy/': '/rest-api/' },
  onProxyReq: async function (proxyReq, req, res) {
    if (!req.header("auth-token")) {
      try {
        const authResult = await requestPromise({
          url: '/rest-api/auth',
          method: 'POST',
          json: { "username": "user", "password": "pass" }
        });
        // 解析返回的token
        const token = authResult.body.token;
        proxyReq.setHeader("auth-token", token);
      } catch (error) {
        console.error('获取token失败:', error);
        res.status(500).send('Failed to obtain authentication token');
        return;
      }
    }
  }
});

额外优化建议

  • 添加token缓存:如果每个无token的请求都去调用/rest-api/auth,会给目标API带来不必要的压力。可以把获取到的token和过期时间存在变量里,下次请求先检查token是否有效,无效再重新获取。
  • 确保auth接口路径正确:注意/rest-api/auth的URL是否需要完整域名(比如http://your-rest-api-domain/rest-api/auth),避免请求到代理服务器本地导致404。
  • 错误处理要完善:如果获取token失败,一定要主动给客户端返回错误响应,避免客户端一直处于等待状态。

内容的提问来源于stack exchange,提问作者Will

火山引擎 最新活动