能否用NewType惯用法适配跨Crate类型?rustls适配worker::Socket遇阻
在Cloudflare Worker中为worker::Socket添加TLS/HTTPS支持(适配rustls)
问题核心
worker::Socket未实现std::io::Read/Write同步IO trait,且本身是异步API;而rustls的同步Stream依赖同步IO,同时Cloudflare Worker的WASM环境不允许阻塞式同步IO,因此必须适配异步IO接口来解决问题。
解决方案:rustls异步API + Socket适配器
1. 实现AsyncRead/AsyncWrite适配器
worker::Socket原生已实现异步读写的底层逻辑,只需创建适配器将其转换为futures_io::AsyncRead和AsyncWrite(rustls异步API依赖的trait):
use futures_io::{AsyncRead, AsyncWrite}; use worker::Socket; use std::pin::Pin; use std::task::{Context, Poll}; // 包装worker::Socket的适配器 pub struct SocketAdapter(Socket); impl SocketAdapter { pub fn new(socket: Socket) -> Self { Self(socket) } } // 转发异步read调用 impl AsyncRead for SocketAdapter { fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll<std::io::Result<usize>> { Pin::new(&mut self.0).poll_read(cx, buf) } } // 转发异步write/flush/close调用 impl AsyncWrite for SocketAdapter { fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<std::io::Result<usize>> { Pin::new(&mut self.0).poll_write(cx, buf) } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { Pin::new(&mut self.0).poll_flush(cx) } fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { Pin::new(&mut self.0).poll_close(cx) } }
2. 使用rustls异步流包装Socket
用rustls::StreamAsync替代同步Stream,配合异步客户端连接完成TLS握手:
use rustls::client::ClientConnection; use rustls::StreamAsync; use std::sync::Arc; use futures_util::io::{AsyncReadExt, AsyncWriteExt}; async fn establish_tls_connection(res: /* 你的目标地址结构体 */) -> worker::Result<()> { // 构建rustls客户端配置 let root_store = rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); let config = rustls::ClientConfig::builder_with_provider(rustls_rustcrypto::provider().into()) .with_safe_default_protocol_versions() .unwrap() .with_root_certificates(root_store) .with_no_client_auth(); // 创建客户端TLS连接 let server_name = res.host.clone().try_into().unwrap(); let conn = ClientConnection::new(Arc::new(config), server_name).unwrap(); // 连接Worker Socket并包装适配器 let sock = Socket::builder().connect(res.host, res.port).await?; let mut tls_stream = StreamAsync::new(conn, SocketAdapter::new(sock)); // 示例:发送HTTP请求并读取响应 tls_stream.write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n").await?; let mut buf = Vec::new(); tls_stream.read_to_end(&mut buf).await?; console_log!("Response: {}", String::from_utf8_lossy(&buf)); Ok(()) }
关键说明
- 适配器仅转发worker::Socket原生的异步方法,无需额外逻辑,代码量极小。
- 必须使用rustls的异步
StreamAsync,因为Cloudflare Worker runtime是纯异步环境,不支持阻塞式同步IO。 - 确保依赖中包含
futures-io、futures-util、rustls、rustls-rustcrypto和webpki-roots。
内容的提问来源于stack exchange,提问作者lopass
相关产品推荐
相关产品推荐

