ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Vue3 知识点速查:把 Vite 代理 endpoint 改到 TaoToken 的完整配置清单

Vue3 知识点速查:把 Vite 代理 endpoint 改到 TaoToken 的完整配置清单

1. Vue3 项目本地开发 401 与 local proxy failed 的真实场景

如果你正在用 Vue3 + Vite 做本地开发,大概率遇到过这种画面:页面能打开,接口一调就红,控制台里躺着401 Unauthorized,终端里刷着http proxy error或者local proxy failed。前端代码明明没改,昨天还能跑,今天换了个接口地址就全挂了。这类问题在 Vue3 项目里特别常见,因为 Vite 的 devServer 代理配置和 Vue2 时代的 webpack devServer 写法有差异,很多人直接把老项目的proxyTable搬过来,结果路径重写、环境变量、鉴权头全对不上。

先说清楚这篇要解决什么。核心检索词是Vue3 Vite 代理配置,具体场景是把本地开发时前端发出的请求,通过 Vite 的server.proxy转发到 TaoToken 的 API 通道,让鉴权在代理层统一处理,避免每个请求都手动带 Key,也避免浏览器直连时的跨域和 401。适合谁看:正在用 Vue3 + Vite 做项目、需要调用大模型接口、被 401 和代理失败卡住的前端开发者。如果你只是写纯静态页面不调接口,这篇可以先收藏。

为什么会出现 401?通常有三种来源。第一种是请求根本没带Authorization头,TaoToken 的 API 需要 Bearer Token 鉴权,前端如果只在某个 axios 实例里加了拦截器,换一个 fetch 调用就漏了。第二种是代理转发时把请求头丢了,Vite 的proxy默认会转发大部分头,但如果你用了rewrite或者configure改写了请求,可能把Authorization覆盖掉。第三种是环境变量没生效,.env.local里写了VITE_API_KEY,但代码里读的是import.meta.env.VITE_API_KEY,构建时没注入,运行时就是undefined,请求头变成Bearer undefined,服务端自然返回 401。

local proxy failed则是另一类问题。Vite 的代理基于http-proxy,当目标地址不可达、DNS 解析失败、或者changeOrigin没开导致 Host 头不匹配时,终端就会打印这个错误。还有一种情况是代理路径写错,比如前端请求/api/chat,代理配置的target是https://taotoken.net/api,但rewrite把/api去掉了,实际转发到https://taotoken.net/api/chat还是https://taotoken.net/chat,路径一错,服务端返回 404 或 401,浏览器看到的就是代理失败。

我试过在一个 Vue3 后台项目里,把原本指向自建 mock 服务的代理切到 TaoToken,结果因为rewrite规则写成了path.replace(/^\/api/, ''),导致所有请求都少了/api前缀,TaoToken 的接口全部 401。后来把 rewrite 去掉,改成在target里带上/api,问题立刻消失。这个坑很典型,下面会给出正确的配置片段。

在动手改配置之前,先确认你的项目结构。典型的 Vue3 + Vite 项目根目录下有vite.config.ts、.env.development、.env.local,src里可能有utils/request.ts或api/index.ts。代理配置写在vite.config.ts的server.proxy里,环境变量通过loadEnv读取。如果你用的是create-vite生成的模板,vite.config.ts默认只有插件配置,需要自己加server段。确认这些之后,就可以进入下一步,把 TaoToken 的接入信息准备好。

2. TaoToken 前置准备:Base URL、API Key 与 Model ID 三件套

在改 Vite 代理之前,先把 TaoToken 这边的三件套拿到手,否则代理配好了也不知道往哪转。三件套指的是Base URL、API Key、Model ID,这三个东西缺一个请求都跑不通。Base URL 是接口的根地址,TaoToken 的 API 地址是https://taotoken.net/api,注意这里不带 UTM 参数,UTM 只用于官网跳转统计,API 调用不需要。API Key 是你的鉴权凭证,在控制台的 API Keys 页面创建,创建后只显示一次,复制下来存到本地环境变量里,不要硬编码到代码里提交到 Git。Model ID 是你实际要调用的模型标识,比如claude-sonnet-4-5之类的字符串,具体以控制台模型列表为准。

获取 API Key 的路径:打开 TaoToken 官网https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,登录后进入控制台,找到 API Keys 菜单,点击创建。创建时可以给 Key 起个名字,比如vue3-dev-local,方便区分不同项目。创建完成后立刻复制,页面刷新后就看不到了。如果你已经有 Key,直接复用也行,但建议本地开发用单独的 Key,方便出问题时快速吊销。

拿到 Key 之后,先别急着写代码,用 curl 验证一下 Key 是否有效。这一步很关键,因为如果 Key 本身有问题,后面代理配得再对也是 401。打开终端,执行下面这条命令,把YOUR_API_KEY替换成你实际的 Key:

curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-5", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 16 }'

如果返回里有choices字段,说明 Key 和 Base URL 都没问题。如果返回 401,检查 Key 是否复制完整、有没有多余空格。如果返回 404,检查路径是不是/api/v1/chat/completions,有些模型走的是/api/v1/messages,具体看文档。如果返回model not found,说明 Model ID 写错了,去控制台模型列表里核对。这一步跑通之后,再进入 Vite 代理配置,能省掉大量排查时间。

关于 Model ID,不同模型的标识不一样,有的带版本号,有的带日期后缀。建议在控制台的模型对话页面先手动发一条消息,确认模型可用,再把 Model ID 抄到项目里。TaoToken 的模型对话入口在https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,可以直接在网页上测试。如果你打算长期在项目里用某个模型,建议把 Model ID 也放到环境变量里,方便切换。

还有一个容易被忽略的点:TaoToken 的 API 支持流式返回,Vue3 项目里如果用 fetch 的ReadableStream或者 axios 的onDownloadProgress处理流式数据,代理层需要确保不缓冲响应。Vite 的http-proxy默认是流式转发的,但如果你在configure里加了proxyRes处理,可能会破坏流。这个在后面的配置片段里会注意。三件套准备好之后,就可以开始写vite.config.ts了。

3. 可复制配置:vite.config.ts 代理片段与环境变量写法

这一节是全文的核心,直接给可复制的配置。先看vite.config.ts的完整写法。假设你的项目根目录是my-vue3-app,配置文件路径是my-vue3-app/vite.config.ts。下面这段配置把/api开头的请求代理到 TaoToken,并且自动带上鉴权头:

import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), '') return { plugins: [vue()], server: { port: 5173, proxy: { '/api': { target: 'https://taotoken.net', changeOrigin: true, secure: true, rewrite: (path) => path.replace(/^\/api/, '/api'), configure: (proxy) => { proxy.on('proxyReq', (proxyReq) => { const key = env.VITE_TAOTOKEN_API_KEY if (key) { proxyReq.setHeader('Authorization', `Bearer ${key}`) } }) } } } } } })

这段配置有几个关键点。target写https://taotoken.net,不带/api,因为rewrite里保留了/api前缀,最终转发到https://taotoken.net/api/...。changeOrigin: true必须开,否则 Host 头不匹配会导致代理失败。secure: true表示校验 SSL 证书,本地开发保持 true 即可。configure里的proxyReq钩子从环境变量读取 Key,动态设置Authorization头,这样前端代码里完全不用管鉴权,所有走/api的请求都会自动带上。

环境变量文件放在项目根目录,文件名.env.local,内容如下:

VITE_TAOTOKEN_API_KEY=sk-你的实际Key VITE_TAOTOKEN_MODEL=claude-sonnet-4-5 VITE_TAOTOKEN_BASE_URL=/api

注意VITE_前缀是 Vite 的约定,只有带这个前缀的变量才会暴露给客户端代码。.env.local默认会被 Git 忽略,不要提交。如果你团队协作需要共享非敏感配置,可以放.env.development,但 Key 一定只放.env.local。VITE_TAOTOKEN_BASE_URL设为/api,前端 axios 的baseURL直接读这个值,请求就会走代理。

前端请求层可以这样写,路径src/utils/request.ts:

import axios from 'axios' const request = axios.create({ baseURL: import.meta.env.VITE_TAOTOKEN_BASE_URL || '/api', timeout: 60000, headers: { 'Content-Type': 'application/json' } }) request.interceptors.response.use( (response) => response.data, (error) => { if (error.response?.status === 401) { console.error('鉴权失败,检查 VITE_TAOTOKEN_API_KEY 是否生效') } return Promise.reject(error) } ) export default request

调用时直接request.post('/v1/chat/completions', { model: import.meta.env.VITE_TAOTOKEN_MODEL, messages: [...] }),请求会先到 Vite devServer 的/api,再被代理到 TaoToken,鉴权头由代理层注入。这样前端代码里看不到 Key,也不会因为漏加拦截器导致 401。

如果你用的是settings.json风格的配置管理,比如某些工具链需要 JSON 格式,可以建一个taotoken.config.json:

{ "baseUrl": "https://taotoken.net/api", "apiKeyEnv": "VITE_TAOTOKEN_API_KEY", "model": "claude-sonnet-4-5", "proxyPath": "/api" }

这个文件只作为配置参考,实际运行时还是以vite.config.ts和环境变量为准。注意不要把真实 Key 写进 JSON 文件,只写环境变量名。配置写完后,重启 devServer,npm run dev,让 Vite 重新加载vite.config.ts和环境变量。热更新不会重新读代理配置,必须重启。

4. 验证请求:curl 与浏览器双通道确认鉴权生效

配置改完,怎么确认真的生效了?分两步验证。第一步用 curl 直接打 Vite devServer 的代理地址,第二步在浏览器里看实际请求。先确保 devServer 已经启动,终端显示Local: http://localhost:5173/。然后新开一个终端,执行:

curl -i -X POST http://localhost:5173/api/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-5", "messages": [{"role": "user", "content": "hello"}], "max_tokens": 16 }'

注意这里请求的是localhost:5173,不是taotoken.net,而且没有手动加Authorization头。如果代理配置正确,Vite 会把请求转发到 TaoToken,并在转发时注入 Key。返回结果里应该能看到choices字段。如果返回 401,说明proxyReq钩子没生效,检查env.VITE_TAOTOKEN_API_KEY是否读到了值,可以在configure里加一行console.log('key loaded:', !!key)调试。如果返回 404,检查rewrite和target的组合,确认最终路径是https://taotoken.net/api/v1/chat/completions。

第二步在浏览器里验证。打开 Vue3 页面,触发一个调用接口的操作,然后在 DevTools 的 Network 面板里找到对应的请求。请求 URL 应该是http://localhost:5173/api/v1/chat/completions,状态码 200。点开请求详情,看 Request Headers 里有没有Authorization,注意浏览器里看到的请求头是前端发出的,代理注入的头在浏览器里看不到,所以这里看不到Authorization是正常的。要看代理注入的头,得在终端里看 Vite 的日志,或者在proxyReq钩子里打印。

如果想确认代理层确实注入了头,可以在vite.config.ts的configure里临时加日志:

configure: (proxy) => { proxy.on('proxyReq', (proxyReq) => { const key = env.VITE_TAOTOKEN_API_KEY console.log('[proxy] injecting auth:', !!key) if (key) { proxyReq.setHeader('Authorization', `Bearer ${key}`) } }) proxy.on('error', (err) => { console.error('[proxy] error:', err.message) }) }

重启 devServer 后,每次请求都会在终端打印[proxy] injecting auth: true。如果打印 false,说明环境变量没读到,检查.env.local文件名和位置。Vite 只加载项目根目录下的.env文件,如果你的项目是多包结构,process.cwd()可能不是根目录,需要调整loadEnv的第二个参数。

还有一个验证技巧:用curl直接打 TaoToken 的 API,对比代理请求的返回。如果直连成功、代理失败,问题一定在代理层;如果直连也失败,问题在 Key 或 Model ID。直连命令前面已经给过,把YOUR_API_KEY换成实际值即可。两个通道都跑通后,说明整条链路没问题,可以开始写业务代码了。

5. 本篇常见错误排查:401、local proxy failed、reading choices、OAuth

这一节对照真实报错,逐个排查。第一个高频错误是401 Unauthorized。前面说过三种来源,这里给具体的排查顺序。先看终端有没有[proxy] injecting auth: true,如果没有,说明环境变量没读到,检查.env.local是否在项目根目录、变量名是否以VITE_开头、devServer 是否重启过。如果有injecting auth: true但依然 401,用 curl 直连 TaoToken 验证 Key 本身是否有效。如果直连也 401,去控制台重新生成 Key。如果直连成功、代理 401,检查proxyReq.setHeader是否被后续的rewrite或configure覆盖,确保setHeader在proxyReq事件里执行。

第二个错误是local proxy failed或http proxy error。这个错误通常伴随ECONNREFUSED或ENOTFOUND。ECONNREFUSED表示目标地址拒绝连接,检查target是否写成了http://而不是https://,TaoToken 的 API 是 HTTPS。ENOTFOUND表示 DNS 解析失败,检查target域名拼写,taotoken.net不要写成taotoken.com。还有一种情况是本地网络环境导致 HTTPS 握手失败,可以临时把secure设为false测试,但生产环境不要这么做。如果错误信息里有socket hang up,可能是请求体太大或超时,调整timeout配置。

第三个错误是Cannot read properties of undefined (reading 'choices')。这个报错说明请求返回了,但返回结构里没有choices字段。常见原因是 Model ID 写错,服务端返回了错误信息而不是正常的 completion 结构。排查方法:在request.interceptors.response里打印完整响应,看error.response.data里的error.message。如果是model not found,去控制台核对 Model ID。如果是invalid request,检查请求体格式,messages必须是数组,每个元素有role和content。还有一种情况是流式返回被当成了普通 JSON 解析,如果你用了stream: true,响应是 SSE 格式,不能用response.data.choices直接取,需要逐行解析data:前缀。

第四个错误和 OAuth 相关。有些项目集成了第三方登录或 OAuth 流程,回调地址配的是localhost:5173,但代理把/oauth/callback也转发到了 TaoToken,导致回调失败。解决方法是把 OAuth 相关路径排除在代理之外,在vite.config.ts里加一条更具体的代理规则,或者用bypass函数跳过:

proxy: { '/api': { target: 'https://taotoken.net', changeOrigin: true, bypass: (req) => { if (req.url?.startsWith('/api/oauth')) { return req.url } }, // ...其他配置 } }

bypass返回req.url表示不代理,直接由 Vite 处理。这样 OAuth 回调就不会被转发到 TaoToken。如果你用的是 Claude Code 或 Cline 这类工具,配置里出现auth.json或settings.json,确保 Base URL 写https://taotoken.net/api,Key 写实际值,Model ID 写控制台里的标识,三件套缺一不可。CC Switch 或 Cline MCP 的配置也是同样的三件套逻辑,Base URL、Key、Model ID 都要对。

最后一个容易忽略的错误是代理路径重复。比如target写了https://taotoken.net/api,rewrite又保留了/api,最终路径变成https://taotoken.net/api/api/v1/...,返回 404。检查方法:在proxyReq里打印proxyReq.path,看最终路径是否正确。正确的路径应该是/api/v1/chat/completions,对应target是https://taotoken.net。如果target带了/api,rewrite就要把/api去掉。两种写法二选一,不要混用。

6. 语义一致 CTA:把请求链路统一到 TaoToken 通道

配置跑通之后,你的 Vue3 项目本地开发请求链路就统一了:前端发/api/...,Vite devServer 代理转发,代理层注入鉴权头,TaoToken 返回结果。这条链路的好处是前端代码零鉴权逻辑,换环境只改环境变量,不碰业务代码。如果你还在用直连方式,每个请求手动加Authorization,一旦漏加就 401,排查起来很费时间。

接下来按场景分流。如果你主要是排障和接入,需要经常查 API Key 和接入文档,建议把这两个页面存到书签:API Keys 管理在https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。文档里有不同语言的调用示例,包括 curl、Python、Node.js,对照着改前端请求体格式很方便。

如果你需要先验证模型效果再决定用哪个,去模型对话页面手动测试:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。在网页上发几条消息,确认模型响应速度和输出质量符合预期,再把 Model ID 抄到项目里。这样比在代码里反复试错快得多。

如果你打算长期在项目里用 TaoToken 做编码辅助或 Agent 开发,比如集成到 Claude Code、Cline 或者自建的 coding agent 里,可以了解 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。Coding Plan 针对长期编码场景做了额度优化,适合每天都要调接口的开发者。配置方式和本文的 Vite 代理一样,三件套不变,只是使用场景从本地开发扩展到日常编码工作流。

最后给一个实用技巧:把vite.config.ts里的代理配置抽成一个函数,方便在多个项目里复用。比如建一个proxy.config.ts,导出createProxy(env)函数,不同项目引入后传入自己的环境变量即可。这样下次新项目接入 TaoToken,复制一个文件就行,不用重新写一遍。代理配置里的configure钩子也可以抽出来,统一处理鉴权头注入和错误日志。配置一次,多处复用,这才是把请求链路统一到 TaoToken 通道之后最省事的地方。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进