1. OpenCode 本地代理为什么总在 body 拼接上翻车如果你正在用 OpenCode 这类 Agent 工具并且想让它走自己的统一 API 通道大概率会碰到一个很具体的场景OpenCode 只认 OpenAI 风格的/v1/chat/completions而你的上游通道需要统一 Key、统一入口。于是你在本地起了一个代理负责把 OpenCode 发来的请求接住、拼完整、再转发出去。问题就出在“拼完整”这一步。OpenCode 发出的 HTTP 请求 body 不一定是带Content-Length的一次性写入很多时候是分块传输chunked。Node.js 的req.on(data)每次只给你一个数据片断如果你直接把每个 chunk 当成完整 JSON 去JSON.parse就会看到类似Unexpected end of JSON input或者Unexpected token的报错。更隐蔽的情况是前几个 chunk 恰好拼成了合法 JSON 的前半段解析不报错但字段缺失转发出去后上游返回 400你回头查日志却看不出哪里断了。这篇就聚焦 OpenCode Agent 本地代理下 body 拼接与分块传输的调试链路用 TaoToken 统一 Key 和 API 通道接入本地代理配置。你会拿到可复制的config.toml骨架、settings.json片段以及分块传输的验证动作和报错排查清单。适合已经在跑 OpenCode、想自己写一层本地代理做请求分析或通道统一的开发者。2. TaoToken 前置统一 Key 与 API 通道准备本地代理要转发就得有一个稳定的上游入口。TaoToken 在这里的角色是提供统一的 API 通道和 Key 管理让 OpenCode 的本地代理只需要认一个 base URL 和一把 Key不用在代理里硬编码多个上游。先拿到 Key。打开控制台创建 API Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite创建后你会得到类似sk-xxxx的字符串。这个 Key 就是本地代理转发时放在Authorization: Bearer里的凭证。注意不要在客户端代码里明文提交放到本地代理的环境变量或配置文件里。TaoToken 的 API 入口是https://taotoken.net/api本地代理的上游 base URL 就填这个路径保持 OpenAI 风格即/v1/chat/completions。这样 OpenCode 发到本地代理的请求代理拼完 body 后原样转发到https://taotoken.net/api/v1/chat/completions认证头换成你刚创建的 Key。如果你还没确认模型通道是否通可以先用模型对话页面做一次最小验证https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite这一步的意义是在写代理之前先确认 Key 和通道本身没问题。否则代理报错时你分不清是拼接逻辑错了还是上游认证失败。3. 可复制配置config.toml 骨架与 settings.json 片段OpenCode 的配置一般分两层一层是 OpenCode 自己的config.toml声明 provider 和 base URL另一层是本地代理的settings.json声明监听端口和上游地址。下面给的是骨架字段名按你实际版本微调。先看 OpenCode 侧的config.toml# ~/.config/opencode/config.toml [provider.local_proxy] name local-proxy base_url http://127.0.0.1:8787/v1 api_key sk-local-placeholder model your-model-name [agent] provider local_proxy这里的关键是base_url指向本地代理的/v1而不是直接指向 TaoToken。OpenCode 会把/v1/chat/completions拼到这个 base_url 后面所以本地代理必须监听这个路径。再看本地代理的settings.json{ listen: { host: 127.0.0.1, port: 8787, path: /v1/chat/completions }, upstream: { base_url: https://taotoken.net/api, path: /v1/chat/completions, api_key_env: TAOTOKEN_API_KEY }, body: { max_bytes: 10485760, join_chunks: true, parse_after_end: true }, log: { level: debug, dump_body: false } }join_chunks和parse_after_end是这篇的核心开关。前者表示把所有data事件拼成一个完整字符串后者表示只在end事件触发后才做JSON.parse。max_bytes是保护阈值防止异常大 body 把内存打满。代理的核心拼接逻辑用 Node.js 写出来大概是这样const http require(http); const server http.createServer((req, res) { if (req.method ! POST || req.url ! /v1/chat/completions) { res.writeHead(404); return res.end(not found); } let body ; let size 0; req.on(data, chunk { size chunk.length; if (size 10 * 1024 * 1024) { req.destroy(); return; } body chunk; }); req.on(end, () { let payload; try { payload JSON.parse(body); } catch (e) { res.writeHead(400, { Content-Type: application/json }); return res.end(JSON.stringify({ error: invalid json body })); } // 转发到 TaoToken forward(payload, res); }); }); server.listen(8787, 127.0.0.1);注意body chunk这一行。它看起来简单但前提是chunk是 Buffer 或字符串Node.js 默认给的是 Buffer会隐式转成字符串。如果 body 里有非 UTF-8 字节隐式转换可能出问题稳妥写法是显式chunk.toString(utf8)或者用数组收集后Buffer.concat。4. 验证请求分块传输下 body 拼接是否成功配置写完后不要直接上 OpenCode 跑先用 curl 模拟分块传输确认代理的拼接逻辑是对的。第一种验证带Content-Length的一次性请求。curl -v http://127.0.0.1:8787/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-local-placeholder \ -d {model:your-model-name,messages:[{role:user,content:ping}]}这种请求 Node.js 可能一次就收到完整 bodydata事件只触发一次。如果代理返回正常说明基础转发链路通了。第二种验证强制分块传输。用Transfer-Encoding: chunked并且手动分两次写curl -v http://127.0.0.1:8787/v1/chat/completions \ -H Content-Type: application/json \ -H Transfer-Encoding: chunked \ -H Authorization: Bearer sk-local-placeholder \ --data-binary - EOF {model:your-model-name,messages:[{role:user,content:ping EOF上面这个写法不完整更可靠的方式是用 Node.js 脚本模拟分块const http require(http); const req http.request({ host: 127.0.0.1, port: 8787, path: /v1/chat/completions, method: POST, headers: { Content-Type: application/json, Transfer-Encoding: chunked } }, res { let data ; res.on(data, c data c); res.on(end, () console.log(status:, res.statusCode, body:, data)); }); req.write({model:your-model-name,); setTimeout(() req.write(messages:[{role:user,content:ping}]}), 200); req.end();这个脚本故意把 JSON 切成两段中间隔 200ms。如果代理的join_chunks生效上游会收到完整 JSON 并正常返回如果代理在第一个 chunk 就解析会直接 400。成功的结果是代理日志里能看到data事件触发两次end事件触发一次JSON.parse成功转发后上游返回 200响应体里有正常的choices字段。5. 本篇常见错排查清单报错一Unexpected end of JSON input原因几乎都是JSON.parse写在了data事件里而不是end事件里。检查你的代码parse必须等所有 chunk 到齐。另一个可能是max_bytes太小body 被截断但这种情况通常会先触发req.destroy()。报错二Unexpected token in JSON at position 0说明 body 开头不是{可能是上游返回了 HTML 错误页或者代理把响应体当成了请求体。检查转发逻辑里Content-Type是否被正确设置以及是否误把上游响应写回了请求解析流程。报错三上游返回 401 或 403本地代理转发时没有带上正确的Authorization头或者 Key 从环境变量读取失败。检查TAOTOKEN_API_KEY是否在启动代理的 shell 里 export 了。可以用printenv TAOTOKEN_API_KEY确认。报错四OpenCode 侧一直转圈代理日志没有请求说明 OpenCode 的base_url没指向本地代理或者端口不对。检查config.toml里的base_url是否是http://127.0.0.1:8787/v1以及代理是否真的在 8787 监听。用curl http://127.0.0.1:8787/v1/chat/completions发个 GET 看是否返回 404说明服务活着。报错五分块传输时 body 拼接后多了换行或空格某些客户端在 chunk 之间会插入\r\n如果你手动处理了 chunk 边界可能把分隔符也拼进去了。Node.js 的data事件已经去掉了 chunked 编码的元数据正常情况下不会有多余字符。如果确实有检查是否在chunk.toString()之后又做了trim()或replace。报错六大 body 导致内存飙升body chunk在超大请求下会频繁创建新字符串。如果 OpenCode 发送的上下文很长建议改成数组收集const chunks []; req.on(data, c chunks.push(c)); req.on(end, () { const body Buffer.concat(chunks).toString(utf8); // parse... });这样内存占用更可控也避免了隐式编码转换的问题。6. 接入文档与后续调试入口本地代理跑通后如果你要把它接到更完整的编码工作流里比如让 OpenCode 长时间跑 Agent 任务建议看一下 Coding Plan 的配置方式它涉及更细的通道和额度管理https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite如果你在接入过程中遇到认证或路径问题接入文档里有完整的 endpoint 说明和示例https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite需要重新生成或管理 Key 时回到 API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite最后提醒一个实操细节本地代理的日志级别在调试阶段开到debug但dump_body保持false。因为 OpenCode 的请求 body 里可能包含你的代码片段和上下文打到日志里既占空间又有泄露风险。确认拼接逻辑没问题后把日志级别调回info只保留状态码和耗时。这样你的本地代理既能稳定拼接分块 body又不会在长期运行中留下敏感数据。
企业数字化 ERP 产品动态
相关推荐
短视频公司网站建设方案多少钱?安全落地避坑指南 短视频公司网站建设方案多少钱?安全落地避坑指南 自己不会代码想做网站,最怕的不是贵,而是花了几千块做个“裸奔”站,上线三天就被挂马。很多短视频公司老板觉得,做个展示型官网或者接单落地页,找外包搞定就行,至于多少钱,市场上从3000到5万都有… · 2026/9/27 11:53:18
毕业季AI论文工具怎么选?TaoToken统一Key接入8款论文软件实测配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 11:53:12
监控器芯片:解决MCU死机、误启动与上电异常的硬件哨兵 前阵子调试一台设备,现场反馈“偶发性死机”,客户描述特别玄学:有时候开机上电后屏幕直接不亮,有时候运行中突然卡死,还有时候电源一抖机器就重启。我们这边复现了三天,示波器一挂,才发现问题全… · 2026/9/27 11:53:11
新乡做网站的公司选错坑多?3张图解步骤避坑指南 新乡做网站的公司选错坑多?3张图解步骤避坑指南 改个需求建站公司拖一周,这种憋屈事儿谁没遇上过?在河南新乡找建站团队,不少老板被拖得进度全乱,最后网站上线慢还一堆Bug。今天不聊虚的,直接给你拆解【新乡做网站的公司】筛选逻辑,用【图解步骤】… · 2026/9/27 12:35:01
seo内容优化避坑指南:3个维度判断服务商哪家好 seo内容优化避坑指南:3个维度判断服务商哪家好 域名服务器搞不懂,是不是让你在选择建站服务时心里没底?很多老板一上来就问“哪家好啊”,但没搞清技术底层逻辑,很容易被销售话术带偏。其实, seo内容优化… · 2026/9/27 12:35:01
基于XBRR-24Z8与R7KA8T2LFLCAC的工业双协议无线方案实战 1. 项目缘起与方案选型:为什么是XBRR-24Z8加R7KA8T2LFLCAC1.1 一个真实的需求场景去年底接了个工业传感器联网的活儿,客户现场是个面积超过8000平米的钢结构厂房,需要部署60多个温振一体传感器,同时要满足两个硬性条件:… · 2026/9/27 12:34:55
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01