You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中为API出站请求添加动态及定时过期Token头的方法

Handling Dynamic and Expiring Tokens for Outbound Requests in Node.js

Great question! Let's break this down into two clear parts since you have two distinct token requirements—one that changes with every request, and another that’s cached with a 10-minute expiry. I’ll cover both common scenarios: using a popular HTTP client like Axios (most projects use this) and global interception for all outbound requests (if you need to cover every HTTP call in your app).


Axios has built-in request interceptors that let you modify outgoing requests before they’re sent. This is clean, maintainable, and perfect for most use cases.

1. Add a Per-Request Dynamic Token

This token changes with every request—think signatures based on request details, timestamps, or unique request IDs. We’ll generate it on the fly in the interceptor:

const axios = require('axios');

// Create a reusable Axios instance
const apiClient = axios.create({
  baseURL: 'https://your-api-base-url.com'
});

// Request interceptor for dynamic per-request token
apiClient.interceptors.request.use((config) => {
  // Generate your dynamic token here (replace with your actual logic)
  // Example: Use request method, URL, and timestamp to create a unique token
  const perRequestToken = generateDynamicToken(config.method, config.url, Date.now());
  
  // Add the token to request headers
  config.headers['X-Per-Request-Token'] = perRequestToken;
  
  return config;
}, (error) => {
  // Handle request errors
  return Promise.reject(error);
});

// Example token generation function (customize this for your use case)
function generateDynamicToken(method, url, timestamp) {
  // Could be an HMAC signature, JWT, or any custom logic
  return `${method.toLowerCase()}:${url}:${timestamp}:your-secure-secret`;
}

2. Add a 10-Minute Expiring Cached Token

For this token, we’ll cache it and only refresh it when it’s about to expire. We’ll also handle concurrent requests to avoid duplicate token fetch calls:

let cachedExpiringToken = null;
let tokenExpiryTime = 0;
let tokenFetchPromise = null; // Prevents concurrent token requests

// Extend the interceptor to handle the expiring token
apiClient.interceptors.request.use(async (config) => {
  const now = Date.now();
  
  // Check if token is missing or about to expire (add 10s buffer to avoid race conditions)
  if (!cachedExpiringToken || now >= tokenExpiryTime - 10000) {
    // Reuse an existing token fetch promise if one is already in flight
    if (!tokenFetchPromise) {
      tokenFetchPromise = fetchNewExpiringToken();
    }
    
    try {
      cachedExpiringToken = await tokenFetchPromise;
      tokenExpiryTime = now + 600000; // 10 minutes in milliseconds
    } finally {
      tokenFetchPromise = null; // Reset after fetch completes
    }
  }
  
  // Add the cached token to headers
  config.headers['X-Expiring-Token'] = cachedExpiringToken;
  
  return config;
}, (error) => {
  return Promise.reject(error);
});

// Example function to fetch a new token from your auth service
async function fetchNewExpiringToken() {
  const response = await axios.get('https://your-auth-service.com/api/token');
  return response.data.token;
}

Scenario 2: Global Interception of All HTTP/HTTPS Requests

If your app uses multiple HTTP clients or directly uses Node’s native http/https modules, you can override the core request methods to intercept all outbound requests.

const http = require('http');
const https = require('https');

// Cache for expiring token
let cachedExpiringToken = null;
let tokenExpiryTime = 0;
let tokenFetchPromise = null;

// Wrap the original request methods
function interceptOutboundRequest(options, callback) {
  // Add per-request dynamic token
  const perRequestToken = generateDynamicToken(options.method || 'GET', options.path, Date.now());
  options.headers = options.headers || {};
  options.headers['X-Per-Request-Token'] = perRequestToken;

  // Handle expiring token logic
  const now = Date.now();
  if (!cachedExpiringToken || now >= tokenExpiryTime - 10000) {
    // Use a promise to handle async token fetch without breaking the request flow
    return new Promise(async (resolve, reject) => {
      try {
        if (!tokenFetchPromise) {
          tokenFetchPromise = fetchNewExpiringToken();
        }
        cachedExpiringToken = await tokenFetchPromise;
        tokenExpiryTime = now + 600000;
        tokenFetchPromise = null;
        
        options.headers['X-Expiring-Token'] = cachedExpiringToken;
        // Send the original request
        const req = options.protocol === 'https:' ? https.request(options, callback) : http.request(options, callback);
        resolve(req);
      } catch (err) {
        reject(err);
      }
    });
  } else {
    options.headers['X-Expiring-Token'] = cachedExpiringToken;
    // Send the original request immediately
    return options.protocol === 'https:' ? https.request(options, callback) : http.request(options, callback);
  }
}

// Override native http.request
const originalHttpRequest = http.request;
http.request = function(options, callback) {
  return interceptOutboundRequest({ ...options, protocol: 'http:' }, callback);
};

// Override native https.request
const originalHttpsRequest = https.request;
https.request = function(options, callback) {
  return interceptOutboundRequest({ ...options, protocol: 'https:' }, callback);
};

// Reuse the same token generation and fetch functions from Scenario 1
function generateDynamicToken(method, url, timestamp) {
  return `${method.toLowerCase()}:${url}:${timestamp}:your-secure-secret`;
}

async function fetchNewExpiringToken() {
  return new Promise((resolve, reject) => {
    https.get('https://your-auth-service.com/api/token', (res) => {
      let data = '';
      res.on('data', (chunk) => data += chunk);
      res.on('end', () => resolve(JSON.parse(data).token));
    }).on('error', reject);
  });
}

Key Notes to Avoid Pitfalls

  • Concurrent Request Handling: The tokenFetchPromise variable ensures that multiple requests don’t all hit your token service at once when the token expires—they’ll wait for the in-flight request to complete.
  • Token Refresh Buffer: Adding a 10-second buffer before the token expires ensures you don’t send a request with a token that’s about to expire mid-flight.
  • Customization: Replace the token generation and fetch logic with your actual auth service requirements (e.g., OAuth2 client credentials, JWT refresh tokens).

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:53:27