Skip to content

Commit a3ecbbb

Browse files
committed
docs: convert proxy.ts comments to bilingual (Chinese + English)
1 parent 8b6a9b5 commit a3ecbbb

1 file changed

Lines changed: 28 additions & 4 deletions

File tree

src/common/proxy.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ export type ResolvedProxy = {
1111

1212
/**
1313
* Determine whether a target URL should bypass the proxy based on NO_PROXY.
14+
* 根据 NO_PROXY 判断目标 URL 是否应绕过代理。
1415
*
15-
* Supports:
16-
* - `*` wildcard (bypass everything)
17-
* - Exact hostname match (e.g. `localhost`, `example.com`)
18-
* - Sub-domain wildcard (e.g. `.example.com` matches `api.example.com`)
16+
* Supports / 支持:
17+
* - `*` wildcard (bypass everything) / 通配符(绕过所有地址)
18+
* - Exact hostname match (e.g. `localhost`, `example.com`) / 精确主机名匹配
19+
* - Sub-domain wildcard (e.g. `.example.com` matches `api.example.com`) / 子域名通配
1920
*/
2021
function shouldBypassProxy(targetUrl: string, noProxy: string): boolean {
2122
if (!noProxy.trim()) {
@@ -41,6 +42,7 @@ function shouldBypassProxy(targetUrl: string, noProxy: string): boolean {
4142
for (const entry of entries) {
4243
if (entry.startsWith(".")) {
4344
// ".example.com" matches "api.example.com" and "example.com"
45+
// ".example.com" 同时匹配 "api.example.com" 和 "example.com"
4446
if (hostname.endsWith(entry) || hostname === entry.slice(1)) {
4547
return true;
4648
}
@@ -56,6 +58,9 @@ function shouldBypassProxy(targetUrl: string, noProxy: string): boolean {
5658
* Pick the first non-empty proxy variable from `source`, preferring
5759
* HTTPS_PROXY → HTTP_PROXY → SOCKS_PROXY → SOCKS5_PROXY (case-insensitive
5860
* lowercase fallback for each).
61+
*
62+
* 从 `source` 中取第一个非空的代理变量,优先级:
63+
* HTTPS_PROXY → HTTP_PROXY → SOCKS_PROXY → SOCKS5_PROXY(大小写均兼容)。
5964
*/
6065
function pickProxyVar(source: Record<string, string | undefined>): { url: string; type: ProxyType } | undefined {
6166
const candidates: Array<{ keys: string[]; type: ProxyType }> = [
@@ -78,6 +83,7 @@ function pickProxyVar(source: Record<string, string | undefined>): { url: string
7883

7984
/**
8085
* Pick NO_PROXY from a source (case-insensitive fallback).
86+
* 从 source 中读取 NO_PROXY(兼容小写 no_proxy)。
8187
*/
8288
function pickNoProxy(source: Record<string, string | undefined>): string {
8389
return (
@@ -94,19 +100,28 @@ function pickNoProxy(source: Record<string, string | undefined>): string {
94100
* 3. Process environment variables (both standard `HTTP_PROXY` / `HTTPS_PROXY`
95101
* and `DEEPCODE_`-prefixed variants)
96102
*
103+
* 按以下优先级解析有效代理地址(由低到高):
104+
* 1. 用户级 `settings.json` → `env`
105+
* 2. 项目级 `settings.json` → `env`
106+
* 3. 进程环境变量(标准 `HTTP_PROXY` / `HTTPS_PROXY` 及 `DEEPCODE_` 前缀变体)
107+
*
97108
* Returns `undefined` when no proxy is configured or when NO_PROXY matches.
109+
* 未配置代理或命中 NO_PROXY 时返回 `undefined`。
98110
*/
99111
export function resolveProxyUrl(
100112
targetUrl: string,
101113
projectRoot: string = process.cwd(),
102114
processEnv: SettingsProcessEnv = process.env
103115
): ResolvedProxy | undefined {
104116
// --- Collect proxy vars from each layer ---
117+
// --- 从各配置层收集代理变量 ---
105118
const userEnv = readSettings()?.env ?? {};
106119
const projectEnv = readProjectSettings(projectRoot)?.env ?? {};
107120

108121
// System env includes both standard proxy vars and DEEPCODE_-prefixed ones
109122
// (collectDeepcodeEnv strips the prefix, so DEEPCODE_HTTPS_PROXY → HTTPS_PROXY).
123+
// 系统环境变量同时包含标准代理变量和 DEEPCODE_ 前缀变量
124+
// (collectDeepcodeEnv 会去除前缀,因此 DEEPCODE_HTTPS_PROXY → HTTPS_PROXY)。
110125
const systemProxySource: Record<string, string | undefined> = { ...processEnv };
111126
for (const [key, value] of Object.entries(processEnv)) {
112127
if (key.startsWith("DEEPCODE_") && typeof value === "string") {
@@ -118,19 +133,22 @@ export function resolveProxyUrl(
118133
}
119134

120135
// --- NO_PROXY check (system level takes absolute precedence) ---
136+
// --- NO_PROXY 检查(系统级拥有绝对优先权)---
121137
const systemNoProxy = pickNoProxy(systemProxySource);
122138
if (shouldBypassProxy(targetUrl, systemNoProxy)) {
123139
return undefined;
124140
}
125141

126142
// --- Merge: user < project < system ---
143+
// --- 合并优先级:用户 < 项目 < 系统 ---
127144
const merged: Record<string, string | undefined> = {
128145
...userEnv,
129146
...projectEnv,
130147
...systemProxySource,
131148
};
132149

133150
// NO_PROXY from merged (user/project may also define it, but system wins)
151+
// 合并后的 NO_PROXY(用户/项目也可定义,但系统级优先)
134152
const mergedNoProxy = pickNoProxy(merged);
135153
if (shouldBypassProxy(targetUrl, mergedNoProxy)) {
136154
return undefined;
@@ -141,13 +159,16 @@ export function resolveProxyUrl(
141159

142160
// ---------------------------------------------------------------------------
143161
// Dispatcher cache – avoids re-creating ProxyAgent on every request.
162+
// Dispatcher 缓存 —— 避免每次请求都重建 ProxyAgent。
144163
// ---------------------------------------------------------------------------
145164
let cachedProxyUrl = "";
146165
let cachedDispatcher: ProxyAgent | null = null;
147166

148167
/**
149168
* Return a `ProxyAgent` dispatcher when a proxy is configured for the given
150169
* target URL, or `null` when requests should go direct.
170+
*
171+
* 当目标 URL 命中代理配置时返回 `ProxyAgent` dispatcher,否则返回 `null` 直连。
151172
*/
152173
export function getProxyDispatcher(targetUrl?: string): ProxyAgent | null {
153174
const resolved = resolveProxyUrl(targetUrl ?? "https://api.deepseek.com");
@@ -175,6 +196,9 @@ export function getProxyDispatcher(targetUrl?: string): ProxyAgent | null {
175196
* Fetch wrapper that automatically routes through the configured proxy.
176197
* Use this in place of the global `fetch` for any HTTP request that should
177198
* respect the proxy configuration.
199+
*
200+
* 自动走代理的 fetch 封装。
201+
* 任何需要遵循代理配置的 HTTP 请求均应使用此函数替代全局 `fetch`。
178202
*/
179203
export async function proxyFetch(url: string | URL, init?: RequestInit): Promise<Response> {
180204
const dispatcher = getProxyDispatcher(String(url));

0 commit comments

Comments
 (0)