前言:当“多模态”遇上“前端工程化”
大模型时代,多模态能力让AI不仅能“看懂”图像,还能“理解”文字指令并生成全新的图片。作为前端开发者,我们经常需要在项目里调用LLM接口,例如通义万相(qwen-image)这类生图模型。但一个棘手的问题始终存在:API密钥怎么安全地放在前端项目里?
直接写死在fetch或axios里肯定不行——一旦代码提交到公开仓库,密钥瞬间泄露。有没有一种既能在开发时方便调用,又不会暴露密钥的解决方案?
答案是:Vite + .env。
本文将带你从零搭建一个基于Vite的前端项目,使用通义千问图像生成模型,通过多模态输入(参考图+文字指令)生成高质量图片,并借助import.meta.env安全管理API密钥。
一、为什么选择Vite?—— 现代前端工程化的“大管家”
Vite是一个极速的构建工具,它基于原生ESM(ES Modules)提供秒级启动的热更新体验。更重要的是,Vite内置了对.env环境变量的支持,完美解决密钥硬编码问题。
ESM是什么?
浏览器原生支持的模块化规范,使用<script type="module">引入JS文件,告别webpack复杂的配置。Vite正是利用这一特性,让开发效率直线飙升。
在传统的HTML+JS项目中,我们如果直接写<script src="main.js">,就无法在JS里使用import语法,更无法读取环境变量。而Vite通过开发服务器将所有资源统一管理,让前端代码也能享受后端般的环境配置。
二、项目初始化:从零搭建Vite + 多模态应用
1. 创建Vite项目
打开终端,执行以下命令:
npm init vite@latest qwen-image-demo -- --template vanilla cd qwen-image-demo npm install这里选择
vanilla模板(原生JS),方便理解核心逻辑。你也可以选vue或react,原理完全一样。
2. 配置.env文件——将密钥藏进“保险箱”
在项目根目录创建.env.local文件(注意不要提交到Git):
VITE_QWEN_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx关键规则:
必须以
VITE_开头,Vite才会将这个变量暴露给客户端代码。.env.local会被Vite自动加载,并且通常被.gitignore忽略,保证密钥不会上传。
然后在main.js中读取:
const apiKey = import.meta.env.VITE_QWEN_API_KEY; console.log(apiKey); // 输出你设置的密钥,仅在开发环境可见
import.meta.env是Vite注入的全局对象,类似于Node.js的process.env。由于Vite启动时会将.env内容替换到代码中,最终打包产物里只包含真正用到的变量,且构建时可以进一步做混淆或警告。
3. 编写HTML与JS
修改index.html(Vite默认以此入口):
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>qwen-image-demo</title> </head> <body> <div id="app"></div> <!-- 注意:type="module" 启用ESM模式,Vite会接管该模块 --> <script type="module" src="/src/main.js"></script> </body> </html>创建src/main.js,完整代码如下(带详细注释):
// 读取环境变量中的API密钥 const apiKey = import.meta.env.VITE_QWEN_API_KEY; const root = document.querySelector('#app'); // 调用通义万相生图接口 const generateImage = async () => { const res = await fetch( 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}`, }, // 请求体必须序列化为JSON字符串 body: JSON.stringify({ "model": "qwen-image-2.0-pro", "input": { "messages": [ { "role": "user", "content": [ { // 第一张参考图:人物照片 "image": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250925/thtclx/input1.png" }, { // 第二张参考图:黑色裙子 "image": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250925/iclsnx/input2.png" }, { // 第三张参考图:坐姿动作 "image": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250925/gborgw/input3.png" }, { // 文字指令:融合以上三张图的信息 "text": "图1的女生穿着图2中的黑色裙子按图3的姿势坐下" } ] } ] }, "parameters": { "n": 1, // 生成1张图片 "size": "1024*1536" // 竖屏尺寸 } }) } ); const data = await res.json(); console.log(data); // 解析返回结果中的图片URL const imgUrl = data.output?.choices?.[0]?.message.content[0].image; return imgUrl; }; // 将图片渲染到页面 const renderImage = (imageUrl) => { root.innerHTML = `<img src="${imageUrl}" style="max-width:100%; border-radius:12px;" />`; }; // 主流程 const main = async () => { try { const imageUrl = await generateImage(); if (imageUrl) { renderImage(imageUrl); } else { root.innerText = '生成失败,请检查控制台错误'; } } catch (error) { console.error(error); root.innerText = '请求异常:' + error.message; } }; main();三、代码深度解析
1. 多模态请求的奥秘
通义万相qwen-image-2.0-pro模型支持图文混合输入。上面的content数组同时包含了三张参考图和一段文字描述,模型会根据这些信息“理解”并合成新图像。
image字段:传入可公开访问的图片URL(或Base64编码)。text字段:自然语言指令,比如“图1的女生穿着图2中的黑色裙子按图3的姿势坐下”。这是多模态对齐的关键。
举例:电商场景中,商家想生成“模特穿着新款连衣裙在沙滩上”的图片,就可以提供模特图+连衣裙图+沙滩背景图,加上文字指令“图1模特穿上图2裙子站在图3沙滩上”,模型就能一键生成。
2. fetch调用细节
请求地址:阿里云DashScope的统一多模态生成端点。
认证方式:
Authorization: Bearer ${apiKey}。请求体:
JSON.stringify(...),因为HTTP传输的是文本,需要将JS对象序列化。响应解析:返回结构为
data.output.choices[0].message.content[0].image,得到生成的图片URL。
3. ESM模块化与Vite的热更新
由于<script type="module">,main.js被视为一个ES模块,可以使用import/export语法(本例未使用额外导入,但可以轻松扩展)。Vite开发服务器会监听文件变化并毫秒级热更新,修改代码后页面自动刷新,开发体验极佳。
4. 密钥安全的工程化实践
开发阶段:Vite读取
.env.local中的VITE_QWEN_API_KEY,将其注入到import.meta.env。前端代码中写的是变量名,实际运行时会被替换为真实密钥。构建阶段:运行
npm run build时,Vite会进行静态分析,将import.meta.env.VITE_*替换为具体的字符串值。如果某个VITE_变量未被使用,则不会出现在最终产物中。生产部署:你需要在生产服务器的环境变量里设置相同名称的变量(例如在Netlify/Vercel的配置面板中添加
VITE_QWEN_API_KEY),这样构建时就能正确注入,同时不暴露在代码仓库中。
⚠️ 注意:任何放在前端的密钥理论上都无法做到100%安全,因为用户可以通过开发者工具看到网络请求中的
Authorization头。但使用.env至少能避免密钥被硬编码提交到Git仓库,降低泄露风险。对于高安全场景,建议后端代理请求。
四、运行与测试
在
.env.local中填写你的通义千问API Key(可到阿里云百炼平台申请)。终端执行:
npm run dev。浏览器打开
http://localhost:5173,稍等片刻,页面将显示生成的图片。
你会看到类似下图的效果(实际结果取决于官方示例图片):
https://fakeimg.pl/600x900?text=AI+Generated+Image
控制台会打印完整的响应数据,便于调试。
五、扩展与优化建议
1. 添加用户交互
你可以增加一个文本输入框和上传图片的功能,让用户自定义参考图和指令:
<input type="text" id="prompt" placeholder="输入指令" /> <button id="generateBtn">生成图片</button>然后在JS中获取用户输入,动态构造content数组。
2. 处理加载状态
在generateImage执行期间显示加载动画,提升体验:
root.innerHTML = '<div class="loading">AI正在努力作画...</div>';root.innerHTML = '<div class="loading">AI正在努力作画...</div>';3. 错误处理更友好
检查HTTP状态码和API返回的错误码:
if (!res.ok) { const err = await res.json(); throw new Error(err.message || '请求失败'); }4. 支持多种尺寸
parameters.size可选值:"1024*1024"(正方形)、"768*1024"(竖屏)、"1024*768"(横屏)等。
六、总结
通过本文,你学会了:
使用Vite创建现代前端项目,拥抱ESM原生模块化。
通过
.env文件安全管理API密钥,利用import.meta.env读取,避免硬编码泄露。调用通义万相多模态生图接口,图文混合输入,按指令生成定制化图片。
完整的前端工程化思维:开发、构建、部署环节中的环境变量处理。
多模态能力正在重塑前端开发的边界,而Vite这样的工具则让我们能轻量、优雅地集成AI服务。现在,就去试试创造属于你自己的智能图像应用吧!