ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ripple Node.js 适配器 @ripple-ts/adapter-node:用 Web Request/Response 标准 API 编写 Node 服务器

Ripple Node.js 适配器 @ripple-ts/adapter-node:用 Web Request/Response 标准 API 编写 Node 服务器 Ripple Node.js 适配器 ripple-ts/adapter-node用 Web Request/Response 标准 API 编写 Node 服务器【免费下载链接】ripplethe elegant TypeScript UI framework项目地址: https://gitcode.com/GitHub_Trending/ripple25/rippleripple-ts/adapter-node是 Ripple 元框架metaframework的 Node.js 运行适配器它把 Node 原生的IncomingMessage/ServerResponseAPI 桥接为 Web 标准的Request/Response让服务器处理函数可以直接使用 Fetch API 编写。读完本文你可以掌握serve()的完整配置项端口、静态资源、中间件、代理信任、请求/响应双向桥接的底层实现细节以及如何借助共享包ripple-ts/adapter复用静态资源逻辑在 Node 环境中稳定跑起 Ripple 应用的服务端。定位与安装在 Ripple 的适配器体系中ripple-ts/adapter-node面向标准 Node.js 环境本地开发服务器、自托管部署等。它的核心价值是把平台相关的 HTTP 细节封装掉你的fetch_handler只面对标准的Request/Response不接触 Node 的res.write()等底层 API。安装方式见 packages/adapter-node/README.mdpnpm add ripple-ts/adapter-node # or npm install ripple-ts/adapter-node # or yarn add ripple-ts/adapter-node当前仓库中该包版本为0.3.127见 packages/adapter-node/package.json以 ESM 形式发布type: module入口为src/index.js类型声明位于types/index.d.ts。它唯一的运行时依赖是工作区内的ripple-ts/adapter共享包。最简服务serve() 基本用法import { serve } from ripple-ts/adapter-node; const app serve(async (request) { const url new URL(request.url); if (url.pathname /health) { return new Response(ok); } return new Response(Hello from Ripple adapter-node!, { headers: { content-type: text/plain; charsetutf-8 }, }); }); app.listen(3000);serve(fetch_handler, options?)创建一个 HTTP 服务器适配器参数说明如下fetch_handler(request: Request, platform?: any) Response | PromiseResponse。从源码看packages/adapter-node/src/index.js第二个参数platform实际传入的是{ node_request, node_response }类型定义packages/adapter-node/types/index.d.ts明确了这一点——当你的处理函数确需访问 Node 原生对象例如直接操作 socket 或提前写响应时可用到它。options.port默认3000options.hostname默认localhostoptions.static默认启用在中间件/处理函数之前提供静态文件详见后文options.middleware可选Node 风格中间件先于fetch_handler执行options.trustProxy默认false是否信任x-forwarded-*头详见后文返回值是一个含两个方法的对象源码listen(port?)启动服务器并返回 NodeServer实例不传端口时回落到options.portclose()关闭服务器。请求桥接URL 构造与代理头信任入站方向的桥接由node_request_to_web_request()完成源码其工作过程包括确定协议与主机默认协议为http主机取host头缺省localhost。若未启用trustProxy会检查node_request.socket.encrypted来判断是否实际为https即直连 TLS 时自动推断协议。信任代理头仅当options.trustProxy为true时才会读取x-forwarded-proto与x-forwarded-host且对以逗号分隔的多值头只取第一个非空值。拷贝全部请求头数组形式头如多个cookie值逐条append保证不丢值。流式请求体对非GET/HEAD方法用Readable.toWeb(node_request)将请求体转为 Web 可读流并设置duplex: half避免整个 body 先缓冲到内存。连接中断传播serve()内部为每个请求创建AbortController并在request的aborted事件或response的close事件上触发abort()源码信号传入Request你的处理函数可通过request.signal感知客户端断开。关于trustProxy有一个重要的安全细节测试用例 packages/adapter-node/tests/serve.test.js 明确验证了默认情况下x-forwarded-*头会被忽略——即使攻击者发送x-forwarded-host: evil.com构造出的 URL 仍使用真实的http协议和真实主机。因此只有在你确实部署在反向代理之后、且确认这些头只能由代理写入时才应显式传入trustProxy: true。启用后同样的测试serve.test.js验证了https://example.com/users?id1这样的 URL 能被正确还原。响应桥接状态码、set-cookie 与流式写出出站方向由web_response_to_node_response()完成源码几个关键行为状态码与状态文本status直接映射到statusCode有statusText时同步写入statusMessage。多个set-cookie优先使用headers.getSetCookie()获取完整 cookie 数组逐个保留没有该方法时退化为headers.get(set-cookie)。测试用例 forwards multiple set-cookie headers 验证了两条set-cookiesessionabc与themedark能同时送达。HEAD 请求不写响应体对HEAD方法或无 body 的响应直接end()对应测试确认客户端收到的 body 为空。流式 bodyResponse.body通过Readable.fromWeb()转换后pipe到ServerResponsebody 流报错时销毁响应连接天然支持大文件/流式响应。未处理错误统一 500若fetch_handler抛出异常且响应尚未开始发送则写入共享包提供的internal_server_error_response()500Internal Server Error见 packages/adapter/src/index.js若响应头已发出则直接结束响应。测试验证了状态码、响应体与content-type。中间件Node 风格可短路 fetch handleroptions.middleware接收标准 Node 三参数中间件(req, res, next)。若中间件已经写出响应调用res.end()或res.headersSent为真则fetch_handler被跳过import { serve } from ripple-ts/adapter-node; const app serve(async () new Response(from handler), { middleware(req, res, next) { if (req.url /legacy) { res.statusCode 200; res.setHeader(content-type, text/plain; charsetutf-8); res.end(from middleware); return; } next(); }, }); app.listen(3000);从源码看这一机制的实现分两步packages/adapter-node/src/index.js中间件在run_node_middleware()中以 Promise 包装执行执行完后若检测到middleware_response.writableEnded || middleware_response.headersSent则返回一个 204 空Response作为短路信号随后serve()发现底层响应已终结便直接返回不再调用你的 fetch handler。测试 short-circuits the handler when middleware already handled the response 用vi.fn()断言了 handler 未被调用而 runs middleware before handler when middleware calls next() 则验证了调用顺序为[middleware, handler]。静态资源服务options.static 与 serveStatic()serveStatic(dir, options?)创建一个 Node 中间件从dir提供静态资产源码。它的行为仅处理GET/HEAD其余方法直接next()放行将 Node 请求临时转换为 WebRequest复用同一套基于Request的静态处理逻辑create_static_handler命中文件则写出未命中则next()回落到后续处理。serve()的options.static在用户中间件/处理函数之前接入同一逻辑参数如下选项默认值说明static.dir见下文静态目录相对路径基于process.cwd()解析static.prefix/URL 前缀仅匹配该前缀之后的路径static.maxAge86400普通文件的缓存秒数static.immutablefalse是否强制不可变缓存static: false—关闭默认静态服务关于dir的默认值需要特别说明README 文档写的是public相对process.cwd()解析但从源码实际实现看src/index.js 中const { dir ., ... } static_options未显式传dir时默认服务的是进程当前目录测试用例 serves files from ./ by default 也印证了这一点。如果你的目录结构依赖public/建议显式传入static: { dir: public }不要依赖默认值。关闭静态服务的用法已被测试覆盖can disable default static serving via options.static falsestatic: false时请求完全交给 fetch handler。缓存策略与 MIME 类型来自共享包README 的 Notes 部分指出静态文件逻辑与 MIME 映射与ripple-ts/adapter共享。确实如此Cache-Control由 get_static_cache_control() 生成命中immutable: true或文件名含哈希特征is_hashed_asset()检测 8 位以上十六进制串时public, max-age31536000, immutable一年不可变缓存否则public, max-age${maxAge}。MIME 类型由 get_mime_type() 按扩展名查表覆盖 html/css/js/json/常见图片/字体/媒体/wasm 等见 MIME_TYPES未知扩展名回落到application/octet-stream。静态服务的安全边界静态路径解析带有目录穿越防护resolve_static_file_path() 将请求路径decodeURIComponent后与基础目录拼接并做前缀校验任何逃逸出dir的路径如../序列都会返回null而不再继续目录路径非文件同样被拒绝不产生目录列表。命中文件时通过createReadStream以流方式返回 bodyHEAD请求只返回头部不返回 bodycreate_static_handler。其他导出runtime 原语与转换函数除 README 中描述的serve/serveStatic外该包还导出若干面向框架内部与 serverless 封装的能力均可在 types/index.d.ts 中查到类型声明runtimeRipple 运行时契约的 Node 实现包含hash(str)SHA-256 十六进制摘要截断到 8 字符与编译器产物保持一致和createAsyncContext()基于AsyncLocalStorage的请求作用域上下文提供run(store, fn)与getStore()。nodeRequestToWebRequest/webResponseToNodeResponse源码注释说明这两个转换函数是为 serverless 函数包装器例如 Vercelre-export 的。事实上工作区内的 packages/adapter-vercel/src/index.js 正是从ripple-ts/adapter-node直接复用runtime与serve——因为 Vercel Serverless Functions 本身就运行在 Node.js 上。如果你需要把这套桥接逻辑嵌入自己的自定义服务器或为其他平台写适配层直接使用这两个转换函数可以获得与serve()完全一致的 URL、头与 body 处理行为。行为速查对照 README Notes 的源码验证行为依据x-forwarded-proto/x-forwarded-host仅在trustProxy: true时生效src/index.js、测试非GET/HEAD请求体以流方式传入src/index.js多个set-cookie全部保留src/index.js、测试handler 未捕获异常返回 500src/index.js、测试静态逻辑与 MIME 映射共享自ripple-ts/adapterpackages/adapter/src/index.js该包通过工作区脚本运行测试pnpm -w test --project adapter-node见 package.json 的scripts.test测试文件 packages/adapter-node/tests/serve.test.js 覆盖了请求映射、中间件顺序、短路、静态服务、HEAD、错误处理等全部关键路径是理解适配器行为的最佳参照。小结ripple-ts/adapter-node用约 400 行源码实现了一个边界清晰的 Node 服务器适配器入站将IncomingMessage转换为携带中止信号与流式 body 的 WebRequest代理头默认不信任出站把 WebResponse状态码、多值set-cookie与流式 body 写回ServerResponse并以共享包统一了静态资源的 MIME 与缓存策略。对需要自托管 Ripple 应用的开发者而言掌握serve()的static、middleware与trustProxy三个选项再辅以serveStatic()的独立用法就足以覆盖绝大多数 Node 部署场景。【免费下载链接】ripplethe elegant TypeScript UI framework项目地址: https://gitcode.com/GitHub_Trending/ripple25/ripple创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表