mirror of
https://github.com/musistudio/claude-code-router.git
synced 2026-07-09 17:18:24 +00:00
Merge pull request #1471 from 810senpai114514/feat/no-proxy
feat: 支持 NO_PROXY 环境变量与 Linux 环境变量代理回退
This commit is contained in:
commit
5ad41aba2b
1 changed files with 60 additions and 3 deletions
|
|
@ -47,7 +47,11 @@ export async function getSystemProxyUrlForProtocol(protocol: "http" | "https" =
|
|||
async function systemProxyUrlForRequest(url: URL): Promise<string | undefined> {
|
||||
const cache = await readSystemProxy();
|
||||
const server = proxyServerForRequest(cache.upstreamProxy, url.protocol === "https:" ? "https" : "http");
|
||||
return server ? formatProxyUrl(server) : undefined;
|
||||
if (server) return formatProxyUrl(server);
|
||||
|
||||
const envProxy = process.env.HTTPS_PROXY || process.env.https_proxy ||
|
||||
process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
return envProxy ? envProxy.trim() : undefined;
|
||||
}
|
||||
|
||||
async function readSystemProxy(): Promise<SystemProxyCache> {
|
||||
|
|
@ -187,12 +191,65 @@ function isHttpUrl(url: URL): boolean {
|
|||
|
||||
function shouldBypassProxy(url: URL): boolean {
|
||||
const hostname = normalizeHostname(url.hostname);
|
||||
return hostname === "localhost" ||
|
||||
if (hostname === "localhost" ||
|
||||
hostname === "127.0.0.1" ||
|
||||
hostname.startsWith("127.") ||
|
||||
hostname === "0.0.0.0" ||
|
||||
hostname === "::1" ||
|
||||
hostname === "0:0:0:0:0:0:0:1";
|
||||
hostname === "0:0:0:0:0:0:0:1") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const noProxy = process.env.NO_PROXY || process.env.no_proxy;
|
||||
if (!noProxy) return false;
|
||||
|
||||
const patterns = noProxy.split(",").map((s) => s.trim()).filter(Boolean);
|
||||
for (const pattern of patterns) {
|
||||
if (pattern === "*") return true;
|
||||
|
||||
if (pattern.startsWith(".")) {
|
||||
if (hostname.endsWith(pattern.toLowerCase()) || hostname === pattern.slice(1).toLowerCase()) return true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pattern.includes("/") && isPlainIp(hostname)) {
|
||||
if (isInCidr(hostname, pattern)) return true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hostname === pattern.toLowerCase()) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isPlainIp(s: string): boolean {
|
||||
return /^\d+\.\d+\.\d+\.\d+$/.test(s);
|
||||
}
|
||||
|
||||
function isInCidr(ip: string, cidr: string): boolean {
|
||||
const [network, prefixStr] = cidr.split("/");
|
||||
const prefix = parseInt(prefixStr, 10);
|
||||
if (isNaN(prefix) || prefix < 0 || prefix > 32) return false;
|
||||
|
||||
const ipInt = ipToInt(ip);
|
||||
const netInt = ipToInt(network);
|
||||
if (ipInt === null || netInt === null) return false;
|
||||
|
||||
const mask = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0;
|
||||
return (ipInt & mask) === (netInt & mask);
|
||||
}
|
||||
|
||||
function ipToInt(ip: string): number | null {
|
||||
const parts = ip.split(".");
|
||||
if (parts.length !== 4) return null;
|
||||
let result = 0;
|
||||
for (const part of parts) {
|
||||
const num = parseInt(part, 10);
|
||||
if (isNaN(num) || num < 0 || num > 255) return null;
|
||||
result = (result << 8) | num;
|
||||
}
|
||||
return result >>> 0;
|
||||
}
|
||||
|
||||
function normalizeHostname(hostname: string): string {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue