返回 API 文档

实操教程

怎么用随机出口节点

目标很简单:让你的每个请求都从不同的手机出口 IP 发出去,并且亲眼确认它真的换了。全程只用 curl,复制粘贴就能跑,预计 5 分钟。

适合第一次接入的同学。不需要懂代理原理,按顺序照做即可;每一步都给了预期结果,对不上就往下翻排错表。

第 0 步:先分清两个「节点」

新手最容易卡在这里 —— 接入的地址和出口的 IP 是两回事,搞混了会一直调错地方。

名词是什么你要做什么
接入节点(入口)你的程序连进来的那台网关服务器,地址长期固定。填在 curl 的 -x 后面,不用改。
出口节点(出口)真正替你访问目标网站的那台手机,决定对方看到的 IP 和归属地。用代理用户名里的 -region-<地区> 选,想随机就在多个地区里随机。

一句话:入口地址一直不变,变的是用户名和连接次数。所以本教程从头到尾只有一个网关地址。

随机出口是怎么发生的

网关只在「新建连接」的那一刻挑出口设备。所以要拿到随机出口,下面三件事缺一不可:

  1. 1

    用户名里不带 -session- 和 -sessTime-。带了就是粘滞会话,网关会刻意把你钉在同一个出口 IP 上。

  2. 2

    每次请求都新建一条连接。HTTP keep-alive 复用旧连接时,请求还在原来那条隧道里跑,出口自然不会变 —— 这是「为什么我的 IP 一直不换」最常见的原因。

  3. 3

    想跨地区随机,就在发起请求前自己从可用地区列表里随机挑一个,拼进用户名。

轮换是「每次重新调度」,不是「保证和上次不同」。地区里在线设备少的时候,连续两次抽到同一台是正常现象。

第 1 步:准备三样东西

全部都在控制台的「代理接入」页面里,打开对照着抄即可。

代理账号与密码

ipx_demo8f2k / YOUR_PASSWORD

注意这不是登录邮箱密码,是代理专用的一组凭证。密码在控制台可以重置,重置后旧密码立即失效。

网关地址

HTTP proxy.gaofengxt.cn:20001 · SOCKS5 proxy.gaofengxt.cn:20002

HTTP 与 SOCKS5 是两个不同端口,别把 SOCKS5 的端口写到 HTTP 示例里。本教程用 HTTP 端口。

可用的出口地区

hangzhou / ningbo

地区代码(slug)是设备池里的城市名。填一个当前没有在线设备的地区会直接失败,所以务必以控制台的列表为准。

第 2 步:一条命令跑通

先不管随机,把最小可用的一条命令跑通。把下面的密码换成你自己的,直接粘进终端:

最小可用命令
curl -x proxy.gaofengxt.cn:20001 \
  -U "ipx_demo8f2k-zone-mob-region-hangzhou:YOUR_PASSWORD" \
  https://ipinfo.io/ip

用户名是三段拼起来的

  • ipx_demo8f2k你的代理账号,控制台里能直接复制。
  • -zone-mob-region-固定中缀,一个字符都不能改、不能少。
  • hangzhou出口地区代码,想换城市就换这一段。

预期结果:终端打印出一行 IP,例如 117.136.38.201。这就是目标网站此刻看到的你的 IP。没有输出或者报错,先跳到最后的排错表。

第 3 步:确认 IP 真的在换

同一条命令连打 5 次,把输出对比一下:

连续 5 次,观察出口 IP
for i in 1 2 3 4 5; do
  curl -s --http1.1 \
    -H 'Connection: close' -H 'Proxy-Connection: close' \
    -x proxy.gaofengxt.cn:20001 \
    -U "ipx_demo8f2k-zone-mob-region-hangzhou:YOUR_PASSWORD" \
    https://ipinfo.io/ip
  echo
done

为什么多了 --http1.1 和两个 Connection: close:curl 默认会尽量复用连接、协商 HTTP/2,同一条连接上的请求走的是同一个出口隧道,IP 就永远不变。显式关掉连接复用,每次请求才会重新调度设备。写代码时同理 —— 别把一个长连接的客户端复用到底。

如果 5 次全都一样:先确认用户名里没有 -session-,再确认上面两个请求头确实加上了。都对但仍然一样,多半是该地区当前只有一台在线设备。

第 4 步:在多个地区之间随机

把地区列表放进数组,每次请求前随机取一个拼进用户名:

随机挑一个出口地区
REGIONS=(hangzhou ningbo)
REGION=${REGIONS[$((RANDOM % ${#REGIONS[@]}))]}

curl -s --http1.1 -H 'Connection: close' \
  -x proxy.gaofengxt.cn:20001 \
  -U "ipx_demo8f2k-zone-mob-region-$REGION:YOUR_PASSWORD" \
  https://ipinfo.io/ip

地区列表要和控制台里「有在线设备」的那些对齐。写死一个池子里没有设备的地区,这一次请求就会失败。

第 5 步:完整脚本(直接抄)

把上面几步合成一个可反复运行的自测脚本:随机地区、强制新建连接、逐次打印出口 IP,最后统计一共命中了多少个不同的出口。

怎么用

  1. 1
    vi test_proxy.sh

    新建文件,把下面整段脚本粘进去保存。

  2. 2
    chmod +x test_proxy.sh

    给脚本加上可执行权限。

  3. 3
    export PROXY_PASSWORD='你的代理密码'

    密码只走环境变量,不要写进脚本,更不要提交到 Git。

  4. 4
    PROXY_USER_PREFIX=你的账号-zone-mob-region COUNT=20 ./test_proxy.sh

    换成你自己的账号前缀后运行;不带任何变量直接运行也可以,用的是下表的默认值。

test_proxy.sh · 随机出口自测脚本
#!/usr/bin/env bash
# 随机出口自测:每次连接随机挑一个出口地区,打印真实出口 IP,最后统计去重结果。
set -u

# ① 网关地址(HTTP 端口),以控制台「代理接入」显示的为准
PROXY_ADDRESS=${PROXY_ADDRESS:-proxy.gaofengxt.cn:20001}
# ② 用户名前缀 = 你的代理账号 + 固定的 -zone-mob-region
PROXY_USER_PREFIX=${PROXY_USER_PREFIX:-ipx_demo8f2k-zone-mob-region}
# ③ 参与随机的出口地区,逗号分隔
REGIONS=${REGIONS:-hangzhou,ningbo}
# ④ 连接次数
COUNT=${COUNT:-10}
# ⑤ 单次连接与整体超时(秒),移动网络建议别调太小
CONNECT_TIMEOUT=${CONNECT_TIMEOUT:-10}
MAX_TIME=${MAX_TIME:-20}
# ⑥ 检测地址,必须返回纯文本 IP
TEST_URL=${TEST_URL:-https://ipinfo.io/ip}

# 密码只从环境变量读,不要写进脚本、更不要提交到 Git
if [ -z "${PROXY_PASSWORD:-}" ]; then
  printf '错误: 请先设置 PROXY_PASSWORD 环境变量。\n' >&2
  exit 2
fi

case "$COUNT" in
  ''|*[!0-9]*|0)
    printf '错误: COUNT 必须是大于 0 的整数。\n' >&2
    exit 2
    ;;
esac

# 把逗号分隔的地区拆成数组
old_ifs=$IFS
IFS=',' read -r -a region_list <<< "$REGIONS"
IFS=$old_ifs
region_count=${#region_list[@]}

if [ "$region_count" -eq 0 ]; then
  printf '错误: REGIONS 至少需要一个地区。\n' >&2
  exit 2
fi

# 临时文件存放每次的 地区+出口IP,退出时自动清理
results_file=$(mktemp "${TMPDIR:-/tmp}/proxy-exit-ip.XXXXXX") || exit 1
trap 'rm -f "$results_file"' EXIT

successful=0
failures=0

printf '网关: %s\n' "$PROXY_ADDRESS"
printf '出口地区: %s\n' "$REGIONS"
printf '连接次数: %s\n\n' "$COUNT"

for ((attempt = 1; attempt <= COUNT; attempt++)); do
  # 随机挑一个出口地区;用户名不带 -session-,即轮换模式
  region=${region_list[$((RANDOM % region_count))]}
  proxy_username="${PROXY_USER_PREFIX}-${region}"

  # --http1.1 + Connection: close 强制每次新建连接 —— 复用连接会一直走同一个出口
  response=$(curl \
    --silent --show-error --fail --http1.1 \
    --connect-timeout "$CONNECT_TIMEOUT" \
    --max-time "$MAX_TIME" \
    -H 'Connection: close' \
    -H 'Proxy-Connection: close' \
    -x "$PROXY_ADDRESS" \
    -U "$proxy_username:$PROXY_PASSWORD" \
    "$TEST_URL" 2>&1)
  curl_status=$?

  if [ "$curl_status" -ne 0 ]; then
    failures=$((failures + 1))
    printf '[%03d/%03d] region=%-10s 失败 curl=%d: %s\n' \
      "$attempt" "$COUNT" "$region" "$curl_status" "$response"
    continue
  fi

  # 纯文本 IP,去掉首尾空白后校验只剩数字和点
  exit_ip=$(printf '%s' "$response" | tr -d '[:space:]')
  case "$exit_ip" in
    ''|*[!0-9.]*)
      failures=$((failures + 1))
      printf '[%03d/%03d] region=%-10s 失败: 检测地址没有返回纯文本 IP\n' \
        "$attempt" "$COUNT" "$region"
      continue
      ;;
  esac

  successful=$((successful + 1))
  printf '%s\t%s\n' "$region" "$exit_ip" >> "$results_file"
  printf '[%03d/%03d] region=%-10s exit_ip=%s\n' \
    "$attempt" "$COUNT" "$region" "$exit_ip"
done

# 汇总:唯一「地区/出口IP」组合越多,说明轮换到的设备越多
if [ "$successful" -gt 0 ]; then
  unique_pairs=$(sort -u "$results_file" | wc -l | tr -d ' ')
else
  unique_pairs=0
fi

printf '\n汇总: 成功=%d 失败=%d 唯一地区/出口IP组合=%d\n' "$successful" "$failures" "$unique_pairs"

if [ "$successful" -gt 0 ]; then
  sort "$results_file" | uniq -c | awk '{
    printf "  region=%s exit_ip=%s 命中=%d\n", $2, $3, $1
  }'
fi

# 有失败就以 1 退出,方便接进 CI 或监控
if [ "$failures" -gt 0 ]; then
  exit 1
fi

可调的环境变量

变量默认值说明
PROXY_PASSWORD代理密码。必填,没设置脚本直接退出。
PROXY_ADDRESSproxy.gaofengxt.cn:20001网关地址(HTTP 端口)。
PROXY_USER_PREFIXipx_demo8f2k-zone-mob-region用户名前缀:你的代理账号加上固定中缀,脚本会自动接上 -<地区>。
REGIONShangzhou,ningbo参与随机的出口地区,逗号分隔。
COUNT10总共发起多少次连接。
CONNECT_TIMEOUT10单次连接超时(秒)。移动出口握手比机房慢,别调太小。
MAX_TIME20单次请求的整体超时(秒),含目标站点响应时间。
TEST_URLhttps://ipinfo.io/ip检测地址,必须返回纯文本 IP。换成你自己的业务地址也可以,但那样就解析不出 IP 了。

主检测地址在移动网络下不通时,换成这两个之一: https://api.ipify.org · http://ip.3322.net

跑起来长这样

示例输出(IP 为示意值)
网关: proxy.gaofengxt.cn:20001
出口地区: hangzhou,ningbo
连接次数: 5

[001/005] region=hangzhou   exit_ip=117.136.38.201
[002/005] region=ningbo     exit_ip=223.104.211.86
[003/005] region=ningbo     exit_ip=223.104.211.86
[004/005] region=hangzhou   exit_ip=39.144.72.14
[005/005] region=hangzhou   exit_ip=117.136.38.201

汇总: 成功=5 失败=0 唯一地区/出口IP组合=3
  region=hangzhou exit_ip=117.136.38.201 命中=2
  region=hangzhou exit_ip=39.144.72.14 命中=1
  region=ningbo exit_ip=223.104.211.86 命中=2

退出码

  • 0全部成功。
  • 1至少有一次失败,细节看逐行输出。
  • 2参数不对或没设置 PROXY_PASSWORD,一次请求都没发。

第 6 步:写进你的程序里

两个要点和 curl 完全一致:用户名不带 session,并且每次请求都用新连接。

Python · requests
import random
import requests
from urllib.parse import quote

GATEWAY = "proxy.gaofengxt.cn:20001"  # 网关 HTTP 端口
ACCOUNT = "ipx_demo8f2k"
PASSWORD = quote("YOUR_PASSWORD", safe="")  # 密码含 @ : / 等字符时必须转义
REGIONS = ["hangzhou", "ningbo"]


def fetch(url: str) -> str:
    region = random.choice(REGIONS)  # 随机出口地区
    username = f"{ACCOUNT}-zone-mob-region-{region}"  # 不带 session = 轮换模式
    proxy = f"http://{username}:{PASSWORD}@{GATEWAY}"
    # Connection: close 让每次请求都新建连接,出口才会换
    resp = requests.get(
        url,
        proxies={"http": proxy, "https": proxy},
        headers={"Connection": "close"},
        timeout=20,
    )
    resp.raise_for_status()

    return resp.text.strip()


for _ in range(5):
    print(fetch("https://ipinfo.io/ip"))
Node.js · undici
// Node 18+;先装 undici:npm i undici
import { ProxyAgent } from "undici";

const GATEWAY = "proxy.gaofengxt.cn:20001";
const ACCOUNT = "ipx_demo8f2k";
const PASSWORD = encodeURIComponent("YOUR_PASSWORD");
const REGIONS = ["hangzhou", "ningbo"];

async function fetchViaRandomExit(url) {
  // 随机出口地区;用户名不带 session 就是轮换模式
  const region = REGIONS[Math.floor(Math.random() * REGIONS.length)];
  const username = `${ACCOUNT}-zone-mob-region-${region}`;
  // 每次请求新建 agent:连接池复用会一直走同一个出口
  const agent = new ProxyAgent(`http://${username}:${PASSWORD}@${GATEWAY}`);

  try {
    const res = await fetch(url, { dispatcher: agent });

    return (await res.text()).trim();
  } finally {
    await agent.close();
  }
}

for (let i = 0; i < 5; i++) {
  console.log(await fetchViaRandomExit("https://ipinfo.io/ip"));
}

排错表

按终端里出现的原话对照着找,左边是现象,右边是怎么处理。

你看到的原因怎么办
curl: (5) Could not resolve proxy网关域名没解析出来。检查本机 DNS 与网络;地址以控制台显示的为准,别手打错字母。
curl: (7) Failed to connect域名解析到了,但端口连不上。确认端口没写错(HTTP 与 SOCKS5 是两个不同端口),再检查本地防火墙或公司出网策略。
curl: (22) … 407代理认证失败。用户名必须带上 -zone-mob-region-<地区> 整段;确认密码没有多余空格,控制台重置过密码就要同步更新。
curl: (28) Operation timed out连上了但没等到响应,通常是移动网络抖动或目标站点慢。把 CONNECT_TIMEOUT / MAX_TIME 调大,并在业务代码里加重试。
503 · NO_ELIGIBLE_DEVICE这个地区当前一台在线设备都没有。换一个地区,或回控制台看哪些地区还有设备。
503 · TUNNEL_UNAVAILABLE地区里有设备,但隧道没建起来(出口设备侧网络异常)。重试或换地区;持续出现请联系技术支持,附上时间点和地区。
403 · TARGET_DENIED目标域名命中了平台的出站黑名单。这类请求不会自动换设备重试,换目标地址;确有正当用途请联系技术支持。
能通,但每次 IP 都一样用户名里带了 session,或者连接被复用了。去掉 -session- 与 -sessTime-,并加上 --http1.1 与 Connection: close;程序里则不要复用同一个连接池。

几个提醒

  • 密码用环境变量传,别写进脚本、别提交仓库。团队共享脚本时尤其注意。
  • 自测也走流量计费。COUNT 调到几百上千之前,先想想这一趟要花多少流量。
  • 需要在一段时间内固定同一个出口 IP(比如登录态、下单流程),用的是粘滞会话而不是轮换,写法见 API 文档的「代理接入」小节。
  • 检测地址返回的 IP 就是目标网站看到的 IP;如果你的业务方要求特定归属地,以这个 IP 的归属为准做验证。

跑通了,接下来看什么

粘滞会话、REST 接口和错误码都在主文档里;可用地区与实时凭证在控制台。