Logo of LexmountLexmount Browser
试验场价格博客预约演示
GitHubX (Twitter)
Logo of LexmountLexmount Browser
产品 · 工程实践

本地代理隧道:让云浏览器访问企业内网

从公司内部代码仓库出发,解释本地代理隧道如何连接云浏览器与本机网络,以及通过 Python 或 Node.js SDK 完成接入的方法。

Logo of LexmountLexmount 浏览器团队
2026/10/1310 分钟阅读
直接访问企业内网失败,与通过本地代理隧道成功传递请求的动画对比

引言

让 Agent 打开公司的代码仓库,找到一个项目,查看最近的合并请求。这项任务的页面操作并不复杂,但放到云浏览器里,第一步就可能停住:仓库地址只能在公司网络中访问。

你的电脑连接着公司 VPN,可以正常打开这个地址;云浏览器运行在另一个网络环境中,既不一定知道内部域名对应的地址,也不一定有通往目标服务的网络路径。把同一个网址交给浏览器,并不会把你电脑的网络环境一起带过去。

Lexmount 的本地代理隧道为这类任务提供了一条连接路径:在能够访问目标站点的电脑上运行 SDK,让指定的云浏览器会话通过这台电脑发送网页流量。浏览器继续在云端执行 JavaScript、处理交互和渲染页面,内网站点的连接则从本机发起。

本文从一次内部代码仓库访问开始,说明这条隧道是什么、SDK 在其中做了什么,以及如何把它接入已有的自动化脚本。

云浏览器与内网站点之间,缺少什么

访问一个网站,浏览器首先需要找到服务器,再建立连接。企业内网往往同时限制这两个环节。

例如,内部代码仓库使用一个只在公司 DNS 中配置的域名。电脑连上 VPN 后,系统可以解析这个域名,网络路由也允许它连接对应的服务器。云浏览器使用自己的网络环境,可能在域名解析时就失败,也可能拿到了地址,却无法连接到目标端口。

因此,解决这类访问问题,需要让请求使用能够到达内网的网络出口,同时使用正确的域名解析环境。仅仅配置一个公共代理地址,不一定能满足这两个条件。

本地代理隧道把这两项工作交给运行 SDK 的电脑:目标域名通过这台电脑的系统 DNS 解析,目标 TCP 连接也从这台电脑发起。 公司或 VPN 提供的 DNS 与路由由此可以参与访问。

这里的“本地”是相对于 SDK 而言的。它可以是开发者的笔记本,也可以是一台部署在公司网络中的运行节点。关键条件是,这台机器能够访问目标网站,并且能够连接 Lexmount 服务的 HTTPS/WSS 入口。

更准确地说,需要确认运行 SDK 的进程能够解析目标域名并建立目标 TCP 连接。如果本机浏览器依赖单独配置的 HTTP/SOCKS 代理或 PAC 脚本才能打开网站,仅凭浏览器能访问还不够:SDK 的目标连接不会自动继承这些浏览器代理设置。

隧道如何把两边连接起来

隧道是一条持续保持、用于转发数据的连接通道。调用 client.tunnels.open() 后,SDK 中的连接器连接 Lexmount 服务;连接器就绪后,调用返回一个隧道对象。

随后,脚本创建云浏览器会话,并把 tunnel.id 填入本地代理配置。这个配置将该会话的网页流量关联到相应隧道。

云浏览器的网页流量经 Lexmount 服务和隧道抵达本机 SDK,再由本机连接企业内网站点;站点响应沿相反方向返回。隧道连接由本机主动向云端建立。

图 1:隧道由本机主动建立;网页请求和响应则沿这条连接双向流动。图中的 SDK 运行在你的 Python 或 Node.js 程序中。动画仅示意流向,实际流量可以通过多个 TCP 流并发往返。

连接由本机主动发起,因此无需为这台电脑配置公网 IP、开放入站监听端口或修改云端 hosts。它需要持续具备出站连接能力,所依赖的 VPN 也需要保持可用。

建立通道后,传输的是浏览器访问网站产生的网络数据。打开页面、加载脚本和图片、调用页面接口,都会产生各自的流量。数据可以在收到后持续转发,无需等本机下载完一整个网页再交给云浏览器。

一次代码仓库访问,分别由谁完成

沿着“打开公司代码仓库”这项任务看,整个过程包含两种不同的工作:控制浏览器,以及为浏览器转发网页流量。

↔横向滑动查看全部
参与者负责的工作
你的脚本或 Agent决定访问哪个页面、执行哪些操作,以及怎样判断任务完成
Lexmount SDK建立和维持隧道、创建会话,并在本机处理目标 DNS、TCP 连接和数据转发
Playwright 等自动化工具通过 CDP 连接云浏览器,下达导航、点击、截图等操作
云浏览器发起网页请求、执行 JavaScript、维护页面状态并渲染页面
内网代码仓库接收请求,按自身的登录与权限规则返回页面或接口数据

例如,脚本调用 page.goto(),让云浏览器打开仓库网址。云浏览器产生访问流量,Lexmount 通过关联的隧道将数据送到本机 SDK;SDK 使用本机网络连接仓库服务,再把返回的数据经隧道传回云浏览器。

云浏览器拿到 HTML 后,会继续加载页面所需的脚本、样式与接口数据。后续点击项目、展开文件目录、打开合并请求,也都在这个浏览器会话中发生。

本机程序负责网络连接和转发,页面处理仍然由云浏览器完成。 你无需在 Python 中自己下载 HTML、解析页面,再把结果拼回浏览器。

这里访问的是代码仓库的 Web 界面。这套示例并没有把 git clone、SSH 或电脑上的所有应用流量接入隧道。

从安装 SDK 到打开第一个内网页面

SDK 是安装到项目中的代码库。安装完成时,它只是磁盘上的文件;脚本导入它并调用相应方法时,这些代码才参与程序执行。

在本地代理场景中,client.tunnels.open() 会启动连接器的工作。你的程序接着创建会话、操作浏览器,连接器则在程序运行期间维持隧道并转发流量。因此,整个任务期间都需要保持这个程序运行。

准备运行环境

Python 和 Node.js SDK 均支持本地代理隧道,建议使用 0.6.1 或更高版本。项目需要具备 custom_proxy 权限,所选区域也需要启用本地代理。隧道与会话必须使用同一项目、API Key 和区域;下面通过复用一个客户端保持这些设置一致。

在能访问目标站点的电脑上,使用 Python 3.10 或更高版本,为包含 Playwright 的示例准备一个虚拟环境:

python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade 'lexmount>=0.6.1' playwright

这是 macOS/Linux 的终端示例。按 Python 快速开始设置 LEXMOUNT_API_KEY 和 LEXMOUNT_PROJECT_ID;如果需要指定区域,再设置 LEXMOUNT_REGION。凭证通过环境变量提供,不写入脚本。

建立隧道、创建会话并访问页面

将下面的代码保存为 visit_internal_site.py:

import os
from urllib.parse import urlsplit

from lexmount import Lexmount
from playwright.sync_api import sync_playwright


def main():
    target = os.environ["TARGET_URL"]
    parsed = urlsplit(target)
    if parsed.scheme not in ("http", "https") or not parsed.hostname:
        raise ValueError("TARGET_URL must be an HTTP(S) URL")

    region = os.getenv("LEXMOUNT_REGION") or None
    with Lexmount(region=region) as client:
        with client.tunnels.open() as tunnel:
            with client.sessions.create(
                browser_mode="normal",
                proxy={"type": "local", "tunnel_id": tunnel.id},
            ) as session:
                print("Session ID:", session.id)
                with sync_playwright() as playwright:
                    browser = playwright.chromium.connect_over_cdp(
                        session.connect_url
                    )
                    try:
                        if not browser.contexts:
                            raise RuntimeError("No browser context available")

                        context = browser.contexts[0]
                        page = (
                            context.pages[0]
                            if context.pages
                            else context.new_page()
                        )
                        page.goto(
                            target,
                            wait_until="domcontentloaded",
                            timeout=60_000,
                        )
                        print("Page title:", page.title())
                        page.screenshot(path="internal-site.png")
                    finally:
                        browser.close()


if __name__ == "__main__":
    main()

将下面的示例地址替换为你有权访问、且本机能够打开的实际 HTTP(S) 地址,再运行脚本:

export TARGET_URL='https://git.corp.example/team/project'
python3 visit_internal_site.py

这里有三个明确的阶段:tunnels.open() 建立隧道,sessions.create() 创建使用该隧道的普通浏览器会话,page.goto() 才真正发起页面访问。浏览器运行在云端,通过 CDP 连接,因此本例无需在本机安装 Chromium。

示例会打印会话 ID 和页面标题、将截图保存到本地的 internal-site.png,随后执行清理。如果要继续执行仓库内的操作,应把它们放在同一个浏览器连接和会话的作用域中。

页面导航完成,并不证明代码仓库已经成功登录。page.goto() 遇到有效的 HTTP 404 或 500 响应也不一定抛出异常;domcontentloaded 更不代表所有资源和业务数据已经加载完成。截图可能显示登录页、错误页、权限提示或尚未加载完的应用界面。实际任务还需要检查响应状态、等待目标元素出现,并确认当前账号能否看到所需项目。

使用 Node.js 或现成示例

Node.js 的流程相同:先调用 client.tunnels.open(),再通过 proxy: { type: 'local', tunnelId: tunnel.id } 创建 browserMode: 'normal' 会话。完整代码与清理方式见本地代理指南。

也可以直接使用维护中的示例项目。完成 Node.js 示例环境安装后,运行:

npm run local-proxy-demo -- --url 'https://git.corp.example/team/project'

完成 Python 示例环境安装后,对应命令是:

python3 local_proxy_demo.py --url 'https://git.corp.example/team/project'

这两个命令需要在各自的示例仓库中执行,安装 SDK 本身不会自动创建这些脚本。它们通过 --url 接收目标地址,在交互式终端中截图后等待按键,再清理退出。

让隧道与任务拥有一致的生命周期

一次任务至少涉及 SDK 客户端、隧道、云浏览器会话和自动化连接四种资源。前面的 Python 示例使用嵌套的 with 与 finally,按依赖顺序建立它们,再按相反顺序执行清理:先关闭浏览器连接,再请求关闭云会话,然后关闭隧道,最后关闭 SDK 客户端。

这个清理顺序在导航失败时同样成立,但执行清理不等于远端资源已经成功释放。SDK 0.6.1 的 session.close() 会将部分关闭失败记录为警告,服务端关闭也可能异步完成。只关闭自动化连接或隧道,都不能代替关闭云浏览器会话,也不能据此认定会话计费已经停止。

如果会话创建超时,服务端可能已经分配了会话,程序却还没有进入它的 with 块。这时,以及程序被强制终止或出现关闭警告时,应结合异常信息、已打印的会话 ID 和控制台检查最终状态,清理遗留会话后再决定是否重试。详见会话生命周期与清理。

断线后,哪些事情会恢复

SDK 默认启用已建立隧道的自动重连。隧道断开时,已有的 TCP 流会失败;在隧道仍有效、网络和凭证允许重连的前提下,重新连接成功后,新建的连接可以使用恢复后的隧道。连接器不会续传中断的 TCP 流或重放请求,也不会改用云端 DNS 或其他代理继续访问。浏览器、页面代码或任务框架的重试行为需要另行考虑,不能由“连接器不重放”推导出整个任务绝不会重复执行。

这对具有写入效果的操作尤其重要。例如,在代码仓库中提交评论时网络断开,浏览器没有收到响应,不代表服务器没有保存评论。重试之前,需要先检查实际结果,避免重复提交。

隧道就绪、会话创建成功和业务操作完成,是三个不同的判断。遇到连接问题,可以先在 SDK 所在电脑上验证目标域名和端口,再检查隧道状态,最后检查云浏览器中的页面。具体错误与对应检查项见本地代理故障排查。

网络可达之后,仍需处理什么

本地代理隧道支持基于 TCP 的 HTTP、HTTPS、WS 和 WSS 网页流量。它是普通云浏览器会话的一种代理方式,当前不适用于 Light/Moli 会话,也不会让独立的 Web Fetch API 自动获得内网访问能力。

接入时还需要区分以下几件事:

  • 网络与登录状态:隧道不会复制本机浏览器的 Cookie 或账号登录态。云浏览器需要完成自己的登录流程,或按站点要求复用已有的持久化 Context。
  • 网络与证书信任:本机信任的私有 CA 不会自动同步到云浏览器。企业证书仍需在云浏览器工作流中正确处理。
  • 本地出口与数据处理位置:请求从本机网络连接目标站点,响应会被传输到云端浏览器处理和渲染。涉及内部资料时,需要按组织允许的范围选择任务和数据。
  • 代理来源与项目额度:本地代理、外部代理和官方代理互斥。本地出口流量与官方代理流量分别统计,浏览器时长、并发和项目权限限制仍然适用。

一条隧道也有自己的有效期和连接数上限。它们与浏览器会话配额是不同的限制,接入长期运行的任务前应查看当前隧道选项与生命周期。

把内网站点接入已有的浏览器工作流

本地代理隧道适合目标站点已经能从某台机器访问、而浏览器任务希望继续在云端执行的场景:公司代码仓库、内部管理系统、VPN 后的测试环境,以及运行节点可以访问的开发站点。

接入之后,脚本仍然通过熟悉的自动化接口导航、读取、点击和截图。变化集中在会话创建阶段:先准备隧道,再为浏览器选择这个网络出口。

从一个本机已能访问的页面开始,确认云浏览器能够打开它,完成登录,再逐步加入真实任务所需的操作。这条从本机网络到云浏览器的连接,让原本停在内网边界外的自动化流程,有了继续执行的路径。

完整接入说明见本地代理指南,代理来源的选择见配置浏览器代理。

引言云浏览器与内网站点之间,缺少什么隧道如何把两边连接起来一次代码仓库访问,分别由谁完成从安装 SDK 到打开第一个内网页面准备运行环境建立隧道、创建会话并访问页面使用 Node.js 或现成示例让隧道与任务拥有一致的生命周期断线后,哪些事情会恢复网络可达之后,仍需处理什么把内网站点接入已有的浏览器工作流
Logo of Lexmount

产品

  • 云浏览器 API
  • 网页内容提取 API
  • 开始使用
  • 模板

资源

  • 高校活动
  • 帮助中心
  • 博客
  • 文档
  • 更新日志
  • 服务状态

公司

  • 关于我们
  • 邮件订阅
  • Cookie政策
  • 浏览器数据处理说明

联系

  • 联系我们
  • GitHub
  • Discord 社群
  • 隐私政策
  • 退款政策
  • 服务条款