个人免费网站开发南通制作网页多少钱
2026/4/18 5:22:59 网站建设 项目流程
个人免费网站开发,南通制作网页多少钱,自己做的创意的网站,网站开发流程 知乎Qwen3-32B开源模型实战#xff1a;Clawdbot Web网关配置与跨域/CORS问题解决 1. 为什么需要Web网关与跨域处理 你是不是也遇到过这样的情况#xff1a;本地跑通了Qwen3-32B模型#xff0c;Ollama服务正常响应#xff0c;Clawdbot前端页面也能打开#xff0c;但一点击发送…Qwen3-32B开源模型实战Clawdbot Web网关配置与跨域/CORS问题解决1. 为什么需要Web网关与跨域处理你是不是也遇到过这样的情况本地跑通了Qwen3-32B模型Ollama服务正常响应Clawdbot前端页面也能打开但一点击发送按钮控制台就报错——CORS policy: No Access-Control-Allow-Origin header is present这不是模型没跑起来也不是代码写错了而是浏览器在“多管闲事”它默认禁止网页向不同源协议、域名、端口任一不同的后端发起请求。而我们典型的开发结构是——前端页面运行在http://localhost:3000Clawdbot Web界面Ollama API 默认监听http://localhost:11434/api/chat中间又加了一层代理转发到18789端口三者端口全不一致浏览器直接拦截请求连请求都发不出去。所以网关不是可选项而是必选项CORS不是小问题而是阻断整个交互链路的关键门槛。本文不讲抽象理论只聚焦一件事怎么用最轻量、最稳定、最易维护的方式把Qwen3-32B真正“接进”你的Web聊天界面。2. 整体架构与角色分工2.1 各组件职责一目了然组件运行位置职责默认端口是否暴露给前端Qwen3-32B 模型本地服务器执行推理生成文本——由Ollama托管❌ 不直连Ollama 服务localhost提供标准/api/chat接口11434❌ 浏览器无法直调Clawdbot Web 前端浏览器渲染聊天界面发送请求3000开发或80生产用户直接访问Web 网关代理localhost接收前端请求转发至Ollama注入CORS头18789前端唯一通信目标关键理解Clawdbot前端只和网关说话网关再替它去和Ollama“交涉”。网关的核心任务有三个——把POST /v1/chat/completions这类前端请求改写成 Ollama 能认的/api/chat格式在响应里加上Access-Control-Allow-Origin: *等必要头让浏览器放行处理流式响应SSE把Ollama返回的data: {...}分块正确透传给前端。2.2 为什么选 18789 端口不是随便定的你可能注意到文档里反复出现18789。这不是一个玄学数字而是经过实测验证的“安全端口”它避开了常见服务端口如8080常被其他开发服务占用3000/5000是前端默认端口它高于1024无需 root 权限即可绑定Linux/macOS 下普通用户可直接启动它在10000–20000区间内既不冲突又便于记忆18789 → “要发吧久”谐音提醒这是“对外发请求”的端口。实际部署时你完全可以改成8088或9001只要前后端配置保持一致即可。3. 三步完成网关配置无依赖、纯Node.js我们不引入Nginx、不装Docker、不配K8s——用一个不到50行的gateway.js文件搞定全部逻辑。它轻、快、透明出问题一眼就能定位。3.1 创建网关脚本gateway.js// gateway.js const http require(http); const url require(url); const { parse } require(querystring); // Ollama服务地址确保能从本机curl通 const OLLAMA_BASE_URL http://localhost:11434; const server http.createServer((req, res) { const parsedUrl url.parse(req.url, true); const path parsedUrl.pathname; // 只处理 /v1/chat/completions 请求Clawdbot前端默认路径 if (req.method POST path /v1/chat/completions) { // 设置CORS头允许任意源生产环境请替换为具体域名 res.setHeader(Access-Control-Allow-Origin, *); res.setHeader(Access-Control-Allow-Methods, POST, OPTIONS); res.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization); res.setHeader(Access-Control-Allow-Credentials, true); // 处理预检请求OPTIONS if (req.method OPTIONS) { res.writeHead(200); res.end(); return; } // 构造Ollama请求选项 const options { method: POST, hostname: localhost, port: 11434, path: /api/chat, headers: { Content-Type: application/json, } }; // 创建Ollama请求 const ollamaReq http.request(options, (ollamaRes) { // 将Ollama响应头透传保留流式特性 res.writeHead(ollamaRes.statusCode, ollamaRes.headers); ollamaRes.pipe(res); }); ollamaReq.on(error, (err) { console.error(Ollama request failed:, err); res.writeHead(500, { Content-Type: application/json }); res.end(JSON.stringify({ error: Failed to connect to Ollama })); }); // 将前端请求体原样转发给Ollama let body ; req.on(data, chunk body chunk); req.on(end, () { try { const frontendData JSON.parse(body); // 关键转换将OpenAI格式转为Ollama格式 const ollamaPayload { model: qwen3:32b, // 必须与Ollama中模型名完全一致 messages: frontendData.messages.map(msg ({ role: msg.role, content: msg.content })), stream: frontendData.stream ?? true, options: { temperature: frontendData.temperature ?? 0.7, num_ctx: 32768 // Qwen3-32B推荐上下文长度 } }; ollamaReq.write(JSON.stringify(ollamaPayload)); ollamaReq.end(); } catch (e) { console.error(Parse error:, e); res.writeHead(400, { Content-Type: application/json }); res.end(JSON.stringify({ error: Invalid JSON in request body })); } }); } else { // 其他路径返回404 res.writeHead(404, { Content-Type: text/plain }); res.end(Not Found); } }); const PORT 18789; server.listen(PORT, () { console.log( Clawdbot Web网关已启动); console.log(➡ 前端请请求: http://localhost:${PORT}/v1/chat/completions); console.log(⬅ 网关已连接Ollama: http://localhost:11434); });3.2 启动网关并验证连通性打开终端执行node gateway.js你会看到类似输出Clawdbot Web网关已启动 ➡ 前端请请求: http://localhost:18789/v1/chat/completions ⬅ 网关已连接Ollama: http://localhost:11434接着用curl模拟一次前端请求验证网关是否真正打通curl -X POST http://localhost:18789/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen3:32b, messages: [{role: user, content: 你好你是谁}], stream: false }如果返回包含message: {role: assistant, content: 我是Qwen3...}的JSON说明网关、Ollama、模型三者已全线贯通。3.3 配置Clawdbot前端指向新网关打开Clawdbot项目的前端配置文件通常是src/config.js或.env修改API基础地址# .env VUE_APP_API_BASE_URLhttp://localhost:18789 # 或 React 项目中的 config.ts export const API_BASE_URL http://localhost:18789;然后重启前端服务npm run dev或yarn start。此时前端所有/v1/chat/completions请求都会先打到18789网关再由网关转发给Ollama——跨域问题彻底消失流式响应完整保留。4. 常见CORS问题与精准修复方案即使按上述步骤操作仍可能遇到五花八门的CORS报错。以下是真实项目中高频出现的4类问题及对应解法不绕弯、不猜疑、直接定位根因。4.1 报错Response to preflight request doesnt pass access control check现象浏览器控制台显示OPTIONS请求返回403或500后续POST根本不发出。原因网关未正确处理预检请求OPTIONS或Ollama服务本身拒绝了OPTIONS方法。修复确认gateway.js中if (req.method OPTIONS)分支存在且执行res.end()。不要试图让Ollama处理OPTIONS——它不支持必须由网关拦截并快速响应。4.2 报错The value of the Access-Control-Allow-Origin header contains the invalid value *现象Chrome报错但Firefox能用或带上credentials: true时失败。原因当需要携带Cookie或认证头时Access-Control-Allow-Origin不能为*必须指定确切域名。修复将网关中res.setHeader(Access-Control-Allow-Origin, *)改为// 开发环境 res.setHeader(Access-Control-Allow-Origin, http://localhost:3000); // 生产环境假设部署在 https://chat.yourcompany.com res.setHeader(Access-Control-Allow-Origin, https://chat.yourcompany.com);同时确保前端请求中credentials: include与后端设置严格匹配。4.3 报错No Access-Control-Allow-Headers header is present现象前端设置了Authorization: Bearer xxx或自定义Header但被拦截。原因网关未声明允许该Header。修复在网关CORS头中补充res.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization, X-Requested-With);4.4 报错Failed to fetch但无CORS字样现象控制台只显示网络错误点开Network标签页发现请求状态为(failed)或net::ERR_CONNECTION_REFUSED。原因网关根本没运行或端口被占用或防火墙拦截。排查顺序lsof -i :18789macOS/Linux或netstat -ano | findstr :18789Windows确认端口是否被占用curl -v http://localhost:18789/health若你加了健康检查或curl -v http://localhost:18789看是否返回Not Found证明网关在运行临时关闭防火墙测试。5. 进阶优化让网关更健壮、更易维护基础版网关能跑通但生产环境还需三点加固。5.1 添加请求日志与错误追踪在gateway.js的请求处理开头加入console.log([${new Date().toISOString()}] ${req.method} ${req.url} ← ${req.socket.remoteAddress});在Ollama请求的on(error)回调中不仅打印错误还记录时间戳和请求体摘要脱敏后ollamaReq.on(error, (err) { const logEntry { timestamp: new Date().toISOString(), error: err.message, remoteAddr: req.socket.remoteAddress, requestBodyPreview: body.substring(0, 100) ... }; console.error(GATEWAY_ERROR:, JSON.stringify(logEntry)); // 此处可对接Sentry、写入文件等 });5.2 支持多模型动态路由如果你不止部署了qwen3:32b还有qwen2.5:7b或phi3:mini可扩展网关支持模型名透传// 从请求路径提取模型名例如 /v1/chat/completions/qwen3:32b const modelMatch parsedUrl.pathname.match(/\/v1\/chat\/completions\/(.)/); const targetModel modelMatch ? modelMatch[1] : qwen3:32b; // 在ollamaPayload中使用 model: targetModel,前端请求改为POST /v1/chat/completions/qwen3:32b即可切换模型无需改网关代码。5.3 集成健康检查端点添加一个/health路径供前端或运维监控网关存活状态if (req.method GET path /health) { // 尝试快速探测Ollama是否可达 const healthReq http.request({ hostname: localhost, port: 11434, path: /api/tags, method: GET }, (healthRes) { res.writeHead(200, { Content-Type: application/json }); res.end(JSON.stringify({ status: ok, timestamp: new Date().toISOString() })); }); healthReq.on(error, () { res.writeHead(503, { Content-Type: application/json }); res.end(JSON.stringify({ status: unavailable, reason: Ollama unreachable })); }); healthReq.end(); return; }6. 总结一条清晰、可复现、零踩坑的落地路径回看整个过程你其实只做了三件确定性极高的事明确边界前端只认网关网关只认Ollama各司其职不越界最小实现50行Node.js脚本无框架、无构建、无依赖复制即用精准归因CORS不是玄学是HTTP头的显式声明是预检请求的正确响应是流式数据的无损透传。你不需要成为网络协议专家也不必深究浏览器同源策略的RFC文档。只要记住这个铁律前端能访问的地址必须是网关地址网关返回的响应必须带正确的Access-Control头Ollama的请求体必须是它能解析的格式。其余都是细节优化。现在打开你的Clawdbot页面输入第一句话看着Qwen3-32B以32B参数量带来的扎实回答缓缓浮现——那不是魔法是你亲手搭起的、稳稳当当的数据桥梁。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询