com.jimuwd.xian.registry-proxy 1.0.95 → 1.0.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +29 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ class ConcurrencyLimiter {
34
34
  }
35
35
  }
36
36
  }
37
- const limiter = new ConcurrencyLimiter(10);
37
+ const limiter = new ConcurrencyLimiter(Infinity);
38
38
  function removeEndingSlashAndForceStartingSlash(str) {
39
39
  if (!str)
40
40
  return '/';
@@ -286,6 +286,15 @@ async function writeResponseToDownstreamClient(registryInfo, targetUrl, resToDow
286
286
  }
287
287
  }
288
288
  }
289
+ function getDownstreamClientIp(req) {
290
+ // 如果经过代理(如 Nginx),取 X-Forwarded-For 的第一个 IP
291
+ const forwardedFor = req.headers['x-forwarded-for'];
292
+ if (forwardedFor) {
293
+ return forwardedFor.toString().split(',')[0].trim();
294
+ }
295
+ // 直接连接时,取 socket.remoteAddress
296
+ return req.socket.remoteAddress;
297
+ }
289
298
  export async function startProxyServer(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath, port = 0) {
290
299
  const proxyInfo = await loadProxyInfo(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
291
300
  const registryInfos = proxyInfo.registries;
@@ -295,11 +304,19 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
295
304
  logger.info('HTTPS:', !!proxyInfo.https);
296
305
  let proxyPort;
297
306
  const requestHandler = async (reqFromDownstreamClient, resToDownstreamClient) => {
298
- if (!reqFromDownstreamClient.url || !reqFromDownstreamClient.headers.host) {
307
+ const downstreamUserAgent = reqFromDownstreamClient.headers["user-agent"]; // "curl/x.x.x"
308
+ const downstreamIp = getDownstreamClientIp(reqFromDownstreamClient);
309
+ const downstreamRequestedHttpMethod = reqFromDownstreamClient.method; // "GET", "POST", etc.
310
+ const downstreamRequestedHost = reqFromDownstreamClient.headers.host; // "example.com:8080"
311
+ const downstreamRequestedFullPath = reqFromDownstreamClient.url; // "/some/path?param=1&param=2"
312
+ logger.info(`Received downstream request ${downstreamUserAgent} ${downstreamIp} ${downstreamRequestedHttpMethod} ${downstreamRequestedHost} ${downstreamRequestedFullPath}`);
313
+ if (!downstreamRequestedFullPath || !downstreamRequestedHost) {
314
+ logger.warn(`400 Invalid Request, downstream ${downstreamUserAgent} req.url is absent or downstream.headers.host is absent.`);
299
315
  resToDownstreamClient.writeHead(400).end('Invalid Request');
300
316
  return;
301
317
  }
302
- const fullUrl = new URL(reqFromDownstreamClient.url, `${proxyInfo.https ? 'https' : 'http'}://${reqFromDownstreamClient.headers.host}`);
318
+ const baseUrl = `${proxyInfo.https ? 'https' : 'http'}://${downstreamRequestedHost}`;
319
+ const fullUrl = new URL(downstreamRequestedFullPath, baseUrl);
303
320
  if (!fullUrl.pathname.startsWith(basePathPrefixedWithSlash)) {
304
321
  resToDownstreamClient.writeHead(404).end('Not Found');
305
322
  return;
@@ -307,19 +324,22 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
307
324
  const path = basePathPrefixedWithSlash === '/'
308
325
  ? fullUrl.pathname
309
326
  : fullUrl.pathname.slice(basePathPrefixedWithSlash.length);
310
- // 顺序尝试注册表,获取第一个成功响应
327
+ const search = fullUrl.search || '';
328
+ const targetPath = path + search;
329
+ logger.info(`Proxying to ${targetPath}`);
330
+ // 按配置顺序尝试注册表,获取第一个成功响应
311
331
  let successfulResponseFromUpstream = null;
312
332
  let targetRegistry = null;
313
333
  let targetUrl = null;
314
- for (const registry of registryInfos) {
334
+ for (const registry_i of registryInfos) {
335
+ targetRegistry = registry_i;
336
+ targetUrl = `${targetRegistry.normalizedRegistryUrl}${targetPath}`;
315
337
  if (reqFromDownstreamClient.destroyed) {
316
338
  // 如果下游客户端自己提前断开(或取消)请求,那么这里不再逐个fallback方式请求(fetch)上游数据了,直接退出循环并返回
339
+ logger.warn(`Downstream ${reqFromDownstreamClient.headers["user-agent"]} request is destroyed, no need to proxy request to upstream ${targetUrl} any more.`);
317
340
  return;
318
341
  }
319
- targetRegistry = registry;
320
- const search = fullUrl.search || '';
321
- targetUrl = `${registry.normalizedRegistryUrl}${path}${search}`;
322
- const okResponseOrNull = await fetchFromRegistry(registry, targetUrl, reqFromDownstreamClient, limiter);
342
+ const okResponseOrNull = await fetchFromRegistry(targetRegistry, targetUrl, reqFromDownstreamClient, limiter);
323
343
  if (okResponseOrNull) {
324
344
  successfulResponseFromUpstream = okResponseOrNull;
325
345
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.jimuwd.xian.registry-proxy",
3
- "version": "1.0.95",
3
+ "version": "1.0.97",
4
4
  "description": "A lightweight npm registry proxy with fallback support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",