共计 3310 个字符,预计需要花费 9 分钟才能阅读完成。
背景痛点
在微信小程序中集成 ChatGPT API 时,开发者通常会遇到几个典型问题:

- 跨域限制:微信小程序的网络请求必须使用其提供的 API(如
wx.request),且域名需要配置在后台白名单中。 - 流式响应处理:ChatGPT 的 API 支持流式返回数据,但小程序原生不支持 EventSource,处理起来较为复杂。
- 敏感信息泄露风险:直接在前端调用 API 可能导致 API 密钥暴露。
这些痛点使得集成过程充满挑战,尤其是对于需要实时交互和高安全性的场景。
技术选型
RESTful API vs WebSocket
- RESTful API:
- 优点:实现简单,兼容性好,适合大多数场景。
- 缺点:实时性较差,无法直接处理流式数据。
- WebSocket:
- 优点:支持双向通信,适合实时交互。
- 缺点:小程序兼容性较差,且需要额外的连接管理。
考虑到小程序的特性和开发成本,推荐使用 wx.request 结合 SSE(Server-Sent Events)模拟方案,既能满足实时性需求,又能保持较高的兼容性。
核心实现
带 JWT 鉴权的 API 请求封装
以下是一个带 JWT 鉴权的 API 请求封装示例,包含 token 自动刷新逻辑:
// utils/request.js
const API_BASE_URL = 'https://your-api-endpoint.com';
let token = wx.getStorageSync('token');
const refreshToken = async () => {
try {
const res = await wx.request({url: `${API_BASE_URL}/refresh-token`,
method: 'POST',
header: {'Authorization': `Bearer ${token}`
}
});
token = res.data.token;
wx.setStorageSync('token', token);
return token;
} catch (error) {console.error('Failed to refresh token:', error);
throw error;
}
};
export const request = async (options) => {
try {
const response = await wx.request({
...options,
url: `${API_BASE_URL}${options.url}`,
header: {
...options.header,
'Authorization': `Bearer ${token}`
}
});
if (response.statusCode === 401) {await refreshToken();
return request(options);
}
return response;
} catch (error) {console.error('Request failed:', error);
throw error;
}
};
流式数据分块处理
由于小程序原生不支持 SSE,我们可以通过 wx.request 模拟 SSE 的行为,分块处理流式数据:
// utils/stream.js
export const streamChatGPT = (prompt, onData, onEnd) => {
let buffer = '';
wx.request({
url: 'https://your-api-endpoint.com/chat',
method: 'POST',
data: {prompt},
responseType: 'text',
enableChunked: true,
success(res) {if (res.statusCode === 200) {
buffer += res.data;
const lines = buffer.split('\n');
buffer = lines.pop();
lines.forEach(line => onData(line));
}
},
fail(err) {console.error('Stream request failed:', err);
},
complete() {onEnd();
}
});
};
性能优化
本地缓存策略
通过设置差异化的会话缓存 TTL(Time-To-Live),可以有效减少 API 调用次数:
// utils/cache.js
const CACHE_TTL = {
SHORT: 60 * 1000, // 1 分钟
MEDIUM: 10 * 60 * 1000, // 10 分钟
LONG: 60 * 60 * 1000 // 1 小时
};
export const setCache = (key, value, ttl = CACHE_TTL.MEDIUM) => {const now = Date.now();
wx.setStorageSync(key, { value, expires: now + ttl});
};
export const getCache = (key) => {const cached = wx.getStorageSync(key);
if (!cached) return null;
if (Date.now() > cached.expires) {wx.removeStorageSync(key);
return null;
}
return cached.value;
};
防抖合并高频请求
使用 lodash.throttle 可以避免用户频繁输入时触发多次 API 请求:
import throttle from 'lodash.throttle';
const throttledRequest = throttle(async (prompt) => {
const response = await request({
url: '/chat',
method: 'POST',
data: {prompt}
});
return response.data;
}, 500); // 500 毫秒内只执行一次
安全实践
敏感词过滤
使用正则表达式实现敏感词过滤:
// utils/filter.js
const SENSITIVE_WORDS = ['敏感词 1', '敏感词 2'];
const regex = new RegExp(SENSITIVE_WORDS.join('|'), 'gi');
export const filterSensitiveWords = (text) => {return text.replace(regex, '***');
};
使用微信云开发作为代理层
通过微信云开发作为代理层,可以避免直接暴露 API 密钥和 IP 地址:
// cloud/functions/chat.js
const axios = require('axios');
exports.main = async (event, context) => {const { prompt} = event;
const response = await axios.post('https://api.openai.com/v1/chat/completions', {
model: 'gpt-3.5-turbo',
messages: [{role: 'user', content: prompt}]
}, {
headers: {'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
}
});
return response.data;
};
避坑指南
- iOS 端 SSE 连接不稳定:
-
解决方案:使用
wx.request模拟 SSE,并设置较短的超时时间(如 30 秒),超时后重新连接。 -
输入框频繁触发 API:
-
解决方案:使用防抖(debounce)或节流(throttle)技术,减少不必要的 API 调用。
-
长文本处理性能问题:
- 解决方案:使用
wx.createSelectorQuery分块处理长文本,避免一次性渲染大量数据。
总结
本文详细介绍了在微信小程序中集成 ChatGPT API 的全流程,从技术选型到核心实现,再到性能优化和安全实践,最后列出了生产环境中常见问题的解决方案。通过这些方法,开发者可以更高效、安全地在小程序中实现 ChatGPT 功能。
延伸思考
- 如何在小程序端实现打字机效果?
- 如何进一步优化流式数据的渲染性能?
完整的代码示例可以在 GitHub 仓库 中找到。
