Workers 运行时提供 connect() API,用于从 Workers 创建出站 TCP 连接 ↗。
许多应用层协议构建在传输控制协议(TCP)之上。这些应用层协议(包括 SSH、MQTT、SMTP、FTP、IRC,以及大多数数据库线协议,如 MySQL、PostgreSQL、MongoDB)都需要底层 TCP 套接字 API 才能工作。
connect() 函数返回一个 TCP 套接字,包含可读和可写数据流。只要连接保持打开,您就可以持续读写数据。
connect() 作为运行时 API 提供,通过从 cloudflare:sockets 导入 connect 函数来访问。此过程类似于在 Node.js 中导入内置模块。请参阅以下代码块,了解创建 TCP 套接字、向其写入数据并将套接字的可读端作为响应返回的示例:
import { connect } from 'cloudflare:sockets';
export default {
async fetch(req): Promise<Response> {
const gopherAddr = { hostname: "gopher.floodgap.com", port: 70 };
const url = new URL(req.url);
try {
const socket = connect(gopherAddr);
const writer = socket.writable.getWriter()
const encoder = new TextEncoder();
const encoded = encoder.encode(url.pathname + "\r\n");
await writer.write(encoded);
await writer.close();
return new Response(socket.readable, { headers: { "Content-Type": "text/plain" } });
} catch (error) {
return new Response("Socket connection failed: " + error, { status: 500 });
}
}
} satisfies ExportedHandler;connect(address: SocketAddress | string, options?: optional SocketOptions):Socketconnect()接受 URL 字符串或SocketAddress来定义要连接的主机名和端口号,以及可选的配置对象SocketOptions。它返回Socket实例。
-
hostnamestring- 要连接的主机名。示例:
cloudflare.com。
- 要连接的主机名。示例:
-
portnumber- 要连接的端口号。示例:
5432。
- 要连接的端口号。示例:
-
secureTransport"off" | "on" | "starttls" — Defaults tooff- 指定创建 TCP 套接字时是否使用 TLS ↗。
off— 不使用 TLS。on— 使用 TLS。starttls— 初始不使用 TLS,但允许通过调用startTls()将套接字升级为使用 TLS。
-
allowHalfOpenboolean — Defaults tofalse- 定义 TCP 套接字的可写端是否在文件结束(EOF)时自动关闭。设置为
false时,TCP 套接字的可写端会在 EOF 时自动关闭。设置为true时,TCP 套接字的可写端在 EOF 时保持打开。 - 此选项类似于 Node.js
net模块 ↗ 提供的选项,可与使用该模块的代码互操作。
- 定义 TCP 套接字的可写端是否在文件结束(EOF)时自动关闭。设置为
-
remoteAddressstring | null- 套接字所连接的对等方地址。可能并非始终设置。
-
localAddressstring | null- 此套接字的本地网络端点地址。可能并非始终设置。
-
readable: ReadableStream- 返回 TCP 套接字的可读端。
-
writable: WritableStream- 返回 TCP 套接字的可写端。
- 返回的
WritableStream仅接受Uint8Array或其视图的块。
-
openedPromise<SocketInfo>- 建立套接字连接时此 Promise 会解析;套接字遇到错误时会被拒绝。
-
closedPromise<void>- 套接字关闭时此 Promise 会解析;套接字遇到错误时会被拒绝。
-
close()Promise<void>- 关闭 TCP 套接字。可读和可写流都会被强制关闭。
-
startTls(): Socket- 将不安全的套接字升级为使用 TLS 的安全套接字,返回新的 Socket。请注意,要调用
startTls(),在最初调用connect()创建套接字时必须将secureTransport设置为starttls。
- 将不安全的套接字升级为使用 TLS 的安全套接字,返回新的 Socket。请注意,要调用
许多基于 TCP 的系统(包括数据库和电子邮件服务器)要求客户端在连接时使用 opportunistic TLS(也称为 StartTLS ↗)。在此模式下,客户端首先创建不安全的 TCP 套接字(不使用 TLS),然后将其升级为使用 TLS 的安全 TCP 套接字。connect() API 通过提供 startTls() 方法简化了此过程,该方法返回使用 TLS 的新 Socket 实例:
import { connect } from "cloudflare:sockets"
const address = {
hostname: "example-postgres-db.com",
port: 5432
};
const socket = connect(address, { secureTransport: "starttls" });
const secureSocket = socket.startTls();- 仅当创建初始 TCP 套接字时将
secureTransport设置为starttls,才能调用startTls()。 - 调用
startTls()后,初始套接字会关闭,无法再从中读取或写入。在上面的示例中,startTls()调用后的任何时刻,您都应使用新创建的secureSocket。基于原始套接字的任何现有 reader 和 writer 将不再工作。您必须从新创建的secureSocket创建新的 reader 和 writer。 - 对现有套接字只能调用一次
startTls()。
创建新 TCP 套接字、从套接字读取或向套接字写入时,若要处理错误,请将这些调用包装在 try...catch ↗ 语句块中。以下示例打开与 Google.com 的连接,发起 HTTP 请求并返回响应。如果失败并抛出异常,将返回 500 响应:
import { connect } from 'cloudflare:sockets';
const connectionUrl = { hostname: "google.com", port: 80 };
export interface Env { }
export default {
async fetch(req, env, ctx): Promise<Response> {
try {
const socket = connect(connectionUrl);
const writer = socket.writable.getWriter();
const encoder = new TextEncoder();
const encoded = encoder.encode("GET / HTTP/1.0\r\n\r\n");
await writer.write(encoded);
await writer.close();
return new Response(socket.readable, { headers: { "Content-Type": "text/plain" } });
} catch (error) {
return new Response(`Socket connection failed: ${error}`, { status: 500 });
}
}
} satisfies ExportedHandler<Env>;您可以通过调用套接字上的 close() 来关闭 TCP 连接。这将关闭套接字的可读端和可写端。
import { connect } from "cloudflare:sockets"
const socket = connect({ hostname: "my-url.com", port: 70 });
const reader = socket.readable.getReader();
socket.close();
// After close() is called, you can no longer read from the readable side of the socket
const reader = socket.readable.getReader(); // This fails- 到 Cloudflare IP 范围 ↗ 的出站 TCP 套接字被阻止。
- TCP 套接字不能在全局作用域中创建并在请求之间共享。您应始终在处理器内创建 TCP 套接字(例如
fetch()、scheduled()、queue())或alarm()。 - 每个打开的 TCP 套接字都计入可同时打开的最大连接数。
- 在 Durable Object 内创建时,打开的 TCP 套接字会使 Durable Object 保持在内存中,每个连接最多产生 15 分钟的 duration 费用。15 分钟后,套接字不再保持 Durable Object 存活(套接字本身继续运行),标准驱逐规则 恢复适用。
- 默认情况下,Workers 无法在端口
25上创建出站 TCP 连接以向 SMTP 邮件服务器发送电子邮件。Cloudflare Email Workers 提供用于处理和转发电子邮件的 API。 - 对入站 TCP 连接的支持即将推出 ↗。目前,无法向您的 Worker 发起入站 TCP 连接,例如使用
CONNECTHTTP 方法。
查看使用 TCP Sockets 时可能遇到的常见错误消息说明、含义及解决方法。
您的套接字正在连接到不允许的地址。不允许的地址示例包括 Cloudflare IP、localhost 和私有网络 IP。
如果您需要在端口 80 或 443 上连接到地址以发起 HTTP 请求,请使用 fetch。
您的套接字正在连接回发起出站连接的 Worker。换句话说,Worker 正在连接回自身。目前不支持此操作。
您的套接字正在连接到端口 25 上的地址。这通常是 SMTP 邮件服务器使用的端口。Workers 无法在端口 25 上创建出站连接。请考虑改用 Cloudflare Email Workers。