本文最后更新于 2025年5月15日 晚上
平常使用代理去访问 Github,Google 之类的网站时,只需要在代理软件中启用系统代理就行,这很简单的嘛。
但在终端中,使用 Git 命令去下载 Github 项目或者访问其他需要代理的网站时,啊咧,怎么访问失败了,明明在代理软件中开了系统代理,怎么会访问不了呢,怎么会是呢?
其实代理软件设置系统代理后,只有主动使用系统代理的软件,比如浏览器等,才能吃到代理,正常访问 Github 之类的网站。但一些有自己代理设置的软件,比如终端,并不会主动使用代理,所以就出现开启系统代理后仍然访问不了的问题。
如果代理软件有虚拟网卡模式,或者 TUN 模式,打开后就能简单解决这个问题。
虚拟网卡模式和 TUN 模式可以模拟一张网卡,使所有流量都经过代理软件,这样即使软件不使用系统代理,软件也会走代理。
在代理软件中,还有个全局模式,但实际上并不能让不使用系统代理的软件走代理。嗯?难道全局模式是假的吗?
其实不假,只是全局模式作用和通常想的不一样。
全局模式是指走代理软件的流量全部走代理服务器,如果改成绕过国内则是走代理软件的流量中,一部分仍然直连,一部分走代理服务器。而虚拟网卡模式和 TUN 模式是调整代理软件在系统中的作用范围,禁用时,只有部分的软件走代理软件,启用时,所有的软件都要走代理软件。
听到这,应该知道虚拟网卡模式和 TUN 模式为什么能解决上面的问题了吧。嗯…还是听不懂嘛,没关系,能访问 Google 的话可以自己查找关于代理软件的 TUN 模式的文档哦,还可以去问问 ChatGPT。这东西讲起来内容有些多,就不在这细讲了。
似乎,开了 TUN 模式后,所有软件都会走代理软件了(不知道是错觉还是真的,网络延迟还变高了呢,可能是流量要多经过一次代理软件的虚拟网卡,增加了处理时间了)。但自己只想让终端使用代理,不如换个方式,调整终端的代理设置吧。
终端里通常使用 HTTP_PROXY 和 HTTPS_PROXY 环境变量来配置代理,将变量的值设置为代理服务器的值就行,再设置 NO_PROXY 环境变量来避免奇奇怪怪的问题。比如从代理软件中知道代理服务器地址是 http://127.0.0.1:10808 ,则在不同终端中设置代理的命令如下。
1 2 3 $Env:HTTP_PROXY = "http://127.0.0.1:10808" $Env:HTTPS_PROXY = "http://127.0.0.1:10808" $Env:NO_PROXY = "localhost,127.0.0.1,::1"
MSYS2 / Git Bash / Linux Shell / Unix Shell
1 2 3 export HTTP_PROXY="http://127.0.0.1:10808" export HTTPS_PROXY="http://127.0.0.1:10808" export NO_PROXY="localhost,127.0.0.1,::1"
1 2 3 set HTTP_PROXY=http://127 .0 .0 .1 :10808 set HTTPS_PROXY=http://127 .0 .0 .1 :10808 set NO_PROXY=localhost,127 .0 .0 .1 ,::1
但是命令设置的环境变量只是临时环境变量,呜,好麻烦啊。唔…终端好像能编写函数,像命令一样调用…诶?!编写一个函数来做这种事不就好了嘛。这里就用 Visual Studio Code 来编写函数吧。
PowerShell 是 Windows 系统里比较常用的终端,下面就先打开 PowerShell,把下面的命令复制进 PowerShell 后回车运行一下。
1 2 New-Item -ItemType Directory -Path "$ ([System.Environment]::GetFolderPath(" MyDocuments"))\WindowsPowerShell" New-Item -ItemType File -Path "$ ([System.Environment]::GetFolderPath(" MyDocuments"))\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"
运行后将在 C:\User\YourUserName\Documents\WindowsPowerShell 这个路径创建一个 Microsoft.PowerShell_profile.ps1 文件,这是 PowerShell 的配置文件,可以在里面编写函数。
呀,差点忘了要解锁 PowerShell 运行脚本的限制了,再运行一下下面的命令吧。
1 Set-ExecutionPolicy Unrestricted -Scope CurrentUser
接下来找到那个目录,用 Visual Studio Code 打开吧,把下面的代码复制进去吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 function global :Set-Proxy { param ( $proxy_value ) if ([string ]::IsNullOrEmpty($proxy_value )) { $internet_setting = Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" if ($internet_setting .ProxyEnable -ne 1 ) { Write-Host "未启用系统代理" return } $proxy_addr = $ ($internet_setting .ProxyServer) if (($proxy_addr -match "http=(.*?);" ) -or ($proxy_addr -match "https=(.*?);" )) { $proxy_value = $matches [1 ] $proxy_value = $proxy_value .ToString().Replace("http://" , "" ).Replace("https://" , "" ) $proxy_value = "http://$ {proxy_value}" } elseif ($proxy_addr -match "socks=(.*)" ) { $proxy_value = $matches [1 ] $proxy_value = $proxy_value .ToString().Replace("http://" , "" ).Replace("https://" , "" ) $proxy_value = "socks://$ {proxy_value}" } else { $proxy_value = "http://$ {proxy_addr}" } } $Env:NO_PROXY = "localhost,127.0.0.1,::1" $Env:HTTP_PROXY = $proxy_value $Env:HTTPS_PROXY = $proxy_value Write-Host "设置代理完成, 代理地址: $Env:HTTP_PROXY " }function global :Unset-Proxy { if ([string ]::IsNullOrEmpty($Env:HTTP_PROXY )) { Remove-Item -Path Env:HTTP_PROXY -Force } if ([string ]::IsNullOrEmpty($Env:HTTPS_PROXY )) { Remove-Item -Path Env:HTTPS_PROXY -Force } Write-Host "清除代理完成" }
复制进去后保存一下就行了。等等,PowerShell 的配置文件需要特殊的文件编码来保存哦。在 Visual Studio Code 里按下 Ctrl + Shift + P,顶上就打开 Visual Studio Code 的功能查找,在上面输入 Change File Encoding,可以看到更改文件编码 这个选项,选择一下,再选一下通过编码保存 ,在编码列表里选择 UTF-8 with BOM,大功告成。
现在再重新打开 PowerShell 就可以用上刚刚编写的函数,输入 Set-Proxy 后,终端就配置好代理了,再试试之前的命令去访问 Github 什么的,网络问题都消失了,好神奇,好方便。
嗯… Set-Proxy 这个命令是自动读取系统代理来设置代理的,如果我知道代理地址,比如 http://127.0.0.1:10808 ,想设置成这个呢?这也是可以的哦。只要 Set-Proxy http://127.0.0.1:10808 就行了呢。
不想使用代理了,想清除刚刚设置的代理,该怎么办呢?很简单,把 PowerShell 重新打开就好了嘛,但是…这样有些麻烦。没关系,刚刚编写的函数里就有一个快速清除代理的函数,运行一下 Unset-Proxy 就好了。
MSYS2 / Git Bash / Linux Shell / Unix Shell
有时使用的终端不是 PowerShell,而是这几个,也可以像 PowerShell 一样编写函数呢。打开终端后,用命令新建一个 sh 文件来编写函数。
1 touch "${HOME} /custom_cmd.sh"
运行后会在 /home/YourUserName 这个路径新建一个 custom_cmd.sh 文件(这里要注意一下,MSYS2 / Git Bash 的 home 目录是在安装这个终端的路径中的哦),用 Visual Studio Code 打开这个文件吧,把下面的函数粘贴进去。
在 MSYS2 / Git Bash 中可以通过 cygpath 命令查看 home 目录对应的 Windows 真实路径,用法是cygpath -w "<要查看的路径>"
,比如查看 home 目录的真实路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 get_windows_system_proxy_config_code () { cat <<EOF # 读取注册表配置 \$internet_setting = Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" \$proxy_addr = \$(\$internet_setting.ProxyServer) # 提取代理地址 if ((\$proxy_addr -match "http=(.*?);") -or (\$proxy_addr -match "https=(.*?);")) { \$proxy_value = \$matches[1] # 去除 http / https 前缀 \$proxy_value = \$proxy_value.ToString().Replace("http://", "").Replace("https://", "") \$proxy_value = "http://\${proxy_value}" } elseif (\$proxy_addr -match "socks=(.*)") { \$proxy_value = \$matches[1] # 去除 socks 前缀 \$proxy_value = \$proxy_value.ToString().Replace("http://", "").Replace("https://", "") \$proxy_value = "socks://\${proxy_value}" } else { \$proxy_value = "http://\${proxy_addr}" } if (\$internet_setting.ProxyEnable -eq 1) { Write-Host \$proxy_value } EOF }get_system_proxy_address () { local gsettings_proxy_status local gsettings_http_host local gsettings_http_port local gsettings_http_proxy_config local gsettings_socks_host local gsettings_socks_port local gsettings_socks_proxy_config local kde_proxy_status local kde_http_proxy_config local kde_socks_proxy_config local windows_proxy_config local macos_proxy_config if [[ "${OSTYPE} " == "msys" * ]] || [[ "${OSTYPE} " == "cygwin" * ]]; then windows_proxy_config=$(powershell -c "$(get_windows_system_proxy_config_code) " 2> /dev/null) echo "${windows_proxy_config} " elif [[ "${OSTYPE} " == "linux" * ]]; then gsettings_proxy_status=$(gsettings get org.gnome.system.proxy mode 2> /dev/null | sed "s/'//g" ) kde_proxy_status=$(cat ~/.config/kioslaverc 2> /dev/null | grep "ProxyType" | awk -F 'ProxyType=' '{print $NF}' ) if [[ "${gsettings_proxy_status} " == "manual" ]]; then gsettings_http_host=$(gsettings get org.gnome.system.proxy.http host 2> /dev/null | sed "s/'//g" ) gsettings_http_port=$(gsettings get org.gnome.system.proxy.http port 2> /dev/null) gsettings_socks_host=$(gsettings get org.gnome.system.proxy.socks host 2> /dev/null | sed "s/'//g" ) gsettings_socks_port=$(gsettings get org.gnome.system.proxy.socks port 2> /dev/null) gsettings_http_proxy_config="http://${gsettings_http_host} :${gsettings_http_port} " gsettings_socks_proxy_config="socks://${gsettings_socks_host} :${gsettings_socks_port} " if [[ ! -z "${gsettings_http_host} " ]] && [[ ! -z "${gsettings_http_port} " ]]; then echo "${gsettings_http_proxy_config} " elif [[ ! -z "${gsettings_socks_host} " ]] && [[ ! -z "${gsettings_socks_port} " ]]; then echo "${gsettings_socks_proxy_config} " fi elif [[ "${kde_proxy_status} " == 1 ]]; then kde_http_proxy_config=$(cat ~/.config/kioslaverc 2> /dev/null |\ grep "httpProxy=" |\ awk -F 'httpProxy=' '{gsub(/ /, ":"); print $NF}' \ ) kde_socks_proxy_config=$(cat ~/.config/kioslaverc 2> /dev/null |\ grep "socksProxy=" |\ awk -F 'socksProxy=' '{gsub(/ /, ":"); print $NF}' \ ) if [[ ! -z "${kde_http_proxy_config} " ]]; then echo "${kde_http_proxy_config} " elif [[ ! -z "${kde_socks_proxy_config} " ]]; then echo "${kde_socks_proxy_config} " fi fi elif [[ "${OSTYPE} " == "darwin" * ]]; then macos_proxy_config=$(scutil --proxy 2> /dev/null | awk ' \ /HTTPEnable/ { http_enabled = $3; } \ /HTTPProxy/ { http_server = $3; } \ /HTTPPort/ { http_port = $3; } \ /SOCKSEnable/ { socks_enabled = $3; } \ /SOCKSProxy/ { socks_server = $3; } \ /SOCKSPort/ { socks_port = $3; } \ END { \ if (http_enabled == "1") { \ print "http://" http_server ":" http_port; \ } else if (socks_enabled == "1") { \ print "socks://" socks_server ":" socks_port; \ } \ }' \ ) echo "${macos_proxy_config} " fi }set_proxy () { local proxy_value if [[ -z "$*" ]]; then proxy_value=$(get_system_proxy_address) if [[ -z "${proxy_value} " ]]; then echo "未启用系统代理" return 1 fi else proxy_value=$@ fi export NO_PROXY="localhost,127.0.0.1,::1" export HTTP_PROXY=$proxy_value export HTTPS_PROXY=$proxy_value echo "设置代理完成, 代理地址: ${proxy_value} " }unset_proxy () { unset HTTP_PROXY unset HTTPS_PROXY echo "清除代理完成" }
粘贴后保存一下就行,这里就不需要特意去修改文件保存编码了。Visual Studio Code 默认使用的 UTF-8 来保存文件编码,使用这个编码就行了,这和 PowerShell 有些区别哦。
此时需要知道此时的终端用的是 Bash,Zsh 或者是其他的终端解释器,就用下面的命令去查看吧。
1 echo "${SHELL#/usr/bin/} "
如果显示的是 bash,则配置文件是 .bashrc;如果显示的是 zsh,则配置文件是 .zshrc,显示的是其他的话就自己在 Google 上查找吧,应该都能查到的。一般配置文件都在 /home/YourUserName 这个路径里,没找到对应的配置文件就自己创建一个吧。
然后打开这个配置文件,在配置文件里写下初始化刚刚编写函数的文件的命令。
1 . "${HOME} /custom_cmd.sh"
保存一下,再重启一下终端,此时就可以像 PowerShell 一样中设置代理了,用法和在 PowerShell 中的一样,只不过… Set-Proxy 要替换成 set_proxy,Unset-Proxy 要替换成 unset_proxy,其他的就和 PowerShell 中的一样了。
嗯…总感觉少了点什么…
啊咧,怎么没有在 CMD 中的教程呢?啊哈哈,CMD 我不怎么用,就不教怎么弄了(其实我也不会弄,诶嘿),把在 PowerShell 中的方法扔给 ChatGPT 或者 DeepSeek 这些 AI,让 AI 改成 CMD 上能用的就行了。
听说有些软件只吃 ALL_PROXY 这个环境变量,嗯…我到现在还没遇到那种软件呢,不过遇上的话就把上面的函数改改就行了,应该很简单的吧,而且还有 AI 可以帮你改呢。
这首歌好听,就顺手推荐一下了。
砂糖和盐最好了~