突破语言壁垒:SuperAgent 国际化请求全攻略
你是否曾为多语言网站的 API 请求头疼?用户明明选择了中文界面,后端却返回英文提示?本文将带你掌握 SuperAgent 的国际化请求技术,通过 Accept-Language 头部精准控制服务端响应语言,让全球用户都能获得母语级体验。读完本文你将学会:设置多语言优先级、解析本地化响应、处理编码问题,以及实战调试技巧。
国际化请求核心:Accept-Language 头部
HTTP 协议中的 Accept-Language 头部(语言客户端)是实现国际化的基石。它允许客户端声明自己偏好的自然语言,格式通常为语言代码加地区代码,如 zh-CN(简体中文)、en-US(美式英语),并可通过权重参数 q 指定优先级。
SuperAgent 设置语言偏好的三种方式
基础设置:直接通过 set 方法添加头部
request
.get('/api/user/profile')
.set('Accept-Language', 'zh-CN,zh;q=0.9,en;q=0.8')
.end((err, res) => {
// 处理响应
});
快捷方法:使用 accept 方法简化设置(需配合类型映射)
// 首先在全局配置类型映射 [src/client.js](https://link.gitcode.com/i/0e2e05197b5816c6f60e86e086b1d9f9)
request.types.lang = 'Accept-Language';
// 然后在请求中使用
request
.get('/api/settings')
.accept('lang', 'ja-JP,ja;q=0.9,en-US;q=0.8')
.end(callback);
默认配置:通过 Agent 设置全局默认语言偏好
const agent = request.agent();
agent.set('Accept-Language', 'es-ES,es;q=0.9');
// 后续所有请求自动携带语言偏好
agent.get('/api/help').end(callback);
agent.post('/api/feedback').send(data).end(callback);
语言优先级权重详解
权重值 q 的范围是 0-1(默认 1.0),数字越大优先级越高。以下是一个复杂场景的优先级排序:
| 头部值 | 实际优先级 | 说明 |
|---|---|---|
fr-CA,fr;q=0.9,en;q=0.8,de;q=0.7 | 1. fr-CA → 2. fr → 3. en → 4. de | 加拿大法语优先,其次是通用法语 |
zh-Hans,zh;q=0.5,en-US | 1. en-US (q=1.0) → 2. zh-Hans (q=1.0) → 3. zh (q=0.5) | 未指定权重的 en-US 优先级高于显式 0.5 的中文 |
⚠️ 注意:服务端可能不完全遵循客户端的权重设置,部分 API 仅支持有限的语言集。
响应处理:从头部到内容的本地化解析
SuperAgent 提供了完整的响应处理机制,帮助开发者轻松处理多语言内容。响应对象的 headers 属性包含了服务端返回的 Content-Language 头部,指示实际使用的语言。
解析响应语言信息
request
.get('/api/messages')
.set('Accept-Language', 'fr,fr-FR;q=0.8,en;q=0.5')
.end((err, res) => {
if (err) throw err;
// 获取服务端实际返回的语言 [src/client.js](https://link.gitcode.com/i/74b2e31dde7e3b79667f16ce6dff60a6)
const responseLang = res.headers['content-language'];
console.log(`服务端返回语言: ${responseLang}`);
// 根据语言类型进行不同处理
switch(responseLang) {
case 'zh-CN':
// 处理中文响应
break;
case 'en-US':
// 处理英文响应
break;
default:
// 默认处理
}
});
字符编码自动处理
SuperAgent 会自动处理常见的字符编码,如 UTF-8、ISO-8859-1 等。其内部通过 content-type 头部的 charset 参数识别编码,并在解析前进行转换。关键实现位于 src/utils.js 的 type 函数和 src/client.js 的 _parseBody 方法。
// 响应内容自动解码流程
function _parseBody(str) {
const contentType = this.headers['content-type'];
const charset = contentType.match(/charset=([^;]+)/)?.[1] || 'utf-8';
// 根据 charset 解码字符串
const decoder = new TextDecoder(charset);
const decoded = decoder.decode(str);
// 进一步解析为 JSON/XML 等格式
return this._parser ? this._parser(decoded) : decoded;
}
多语言响应的最佳实践
- 始终检查 Content-Language:不要假设服务端会返回请求的首选语言
- 提供降级方案:当请求语言不可用时,应有默认语言处理逻辑
- 处理 RTL 语言:对阿拉伯语、希伯来语等从右到左的语言,需在前端特殊处理
- 缓存语言偏好:可将用户语言选择存储在 localStorage 中,提升后续体验
实战案例:多语言用户反馈系统
让我们通过一个完整案例,实现支持 12 种语言的用户反馈系统。该系统需要根据用户语言偏好,发送对应语言的表单提示和错误信息。
项目结构与配置
examples/
├── i18n/
│ ├── translations.json # 语言包
│ └── request.js # 国际化请求封装
└── feedback-form.js # 反馈表单实现
核心实现代码
语言包配置 [examples/i18n/translations.json]
{
"en-US": {
"submit": "Submit Feedback",
"success": "Thank you for your feedback!",
"error": {
"required": "This field is required",
"tooLong": "Message cannot exceed 500 characters"
}
},
"zh-CN": {
"submit": "提交反馈",
"success": "感谢您的反馈!",
"error": {
"required": "此字段为必填项",
"tooLong": "留言不能超过 500 字符"
}
},
// 其他语言...
}
请求封装 [examples/i18n/request.js]
const request = require('../../src/client');
const translations = require('./translations.json');
// 检测浏览器语言偏好
function getBrowserLang() {
return navigator.language || navigator.userLanguage || 'en-US';
}
// 创建带语言偏好的请求实例
const i18nRequest = (lang = getBrowserLang()) => {
const req = request.agent();
// 设置 Accept-Language 头部
req.set('Accept-Language', lang);
// 添加响应处理中间件
req.use((req, res, next) => {
// 存储实际使用的语言
req.lang = res.headers['content-language'] || lang.split('-')[0] || 'en';
next();
});
return req;
};
// 获取翻译文本
i18nRequest.t = (key, lang = getBrowserLang()) => {
const keys = key.split('.');
let value = translations[lang] || translations['en-US'];
for (const k of keys) {
if (!value[k]) {
// 回退到英语
value = translations['en-US'];
for (const k2 of keys) {
value = value[k2] || `[Missing translation: ${key}]`;
}
break;
}
value = value[k];
}
return value;
};
module.exports = i18nRequest;
表单实现 [examples/feedback-form.js]
const i18nRequest = require('./i18n/request');
const lang = 'zh-CN'; // 实际应用中从用户设置或浏览器获取
const request = i18nRequest(lang);
const t = i18nRequest.t;
// 渲染表单
document.getElementById('submit-btn').textContent = t('submit', lang);
// 处理提交
document.getElementById('feedback-form').addEventListener('submit', (e) => {
e.preventDefault();
const formData = {
message: document.getElementById('message').value,
email: document.getElementById('email').value
};
request
.post('/api/feedback')
.send(formData)
.end((err, res) => {
if (err) {
// 显示本地化错误信息
const errorEl = document.getElementById('error');
errorEl.textContent = t(`error.${err.code}`, res.req.lang);
errorEl.style.display = 'block';
return;
}
// 显示成功消息
alert(t('success', res.req.lang));
form.reset();
});
});
调试与验证
为确保国际化请求正常工作,可通过以下方式验证:
- 查看请求头:在浏览器开发者工具的 Network 面板中,检查请求的 Accept-Language 头部是否正确设置
- 检查响应头:确认服务端返回的 Content-Language 头部与预期一致
- 测试边缘情况:尝试设置不存在的语言代码,验证服务端的降级处理
高级技巧:动态语言切换与缓存策略
构建语言切换中间件
// 创建语言切换中间件
function languageMiddleware(req, res, next) {
// 从查询参数或 cookie 中获取语言偏好
const lang = req.query.lang || getCookie('preferred-lang');
if (lang) {
req.set('Accept-Language', lang);
// 更新 cookie
setCookie('preferred-lang', lang, { maxAge: 30*24*60*60*1000 });
}
next();
}
// 使用中间件
request.use(languageMiddleware);
实现响应缓存
为提升性能,可对相同语言的响应结果进行缓存:
const responseCache = new Map();
function cacheMiddleware(req, res, next) {
const cacheKey = `${req.method}:${req.url}:${req.headers['accept-language']}`;
// 检查缓存
if (responseCache.has(cacheKey)) {
return res.end(responseCache.get(cacheKey));
}
// 缓存响应
const originalEnd = res.end;
res.end = function(data) {
responseCache.set(cacheKey, data);
originalEnd.call(this, data);
};
next();
}
// 添加缓存有效期清理
setInterval(() => {
responseCache.clear();
}, 3600*1000); // 每小时清理一次缓存
常见问题与解决方案
Q: 服务端忽略 Accept-Language 设置怎么办?
A: 首先检查请求头是否正确发送,可通过 src/client.js 中的代码确认头部设置逻辑。若服务端仍不响应,可能需要通过查询参数传递语言偏好,如 ?lang=zh-CN。
Q: 如何处理右-to-left (RTL) 语言?
A: 可根据响应的 Content-Language 动态添加 CSS 类:
if (['ar', 'he', 'fa'].includes(res.headers['content-language'])) {
document.documentElement.classList.add('rtl');
} else {
document.documentElement.classList.remove('rtl');
}
Q: 多语言环境下的日期和数字格式化?
A: 结合 Intl API 和响应语言信息:
const formatter = new Intl.DateTimeFormat(res.req.lang, {
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(formatter.format(new Date()));
总结与最佳实践
SuperAgent 提供了简洁而强大的 API 来处理国际化请求,核心要点包括:
- 正确设置 Accept-Language 头部,指定语言优先级
- 利用响应对象的 headers 属性获取实际使用的语言
- 实现客户端语言缓存与切换机制
- 对不同语言的文本和布局进行适配处理
官方文档中的 请求头设置章节 和 响应处理指南 提供了更多底层实现细节。遵循本文介绍的方法,你可以为全球用户提供无缝的本地化体验,真正突破语言壁垒。
建议在实际项目中建立完善的国际化测试流程,覆盖主要目标语言,并监控服务端的语言支持情况。随着用户群体的全球化,良好的国际化实现将成为产品竞争力的重要组成部分。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



