is-china-user
v1.7.0
Published
判断当前浏览器环境是否更像中国用户 / 中国地区设备。
Readme
🇨🇳 isChinaUser
判断当前浏览器环境是否更像中国用户 / 中国地区设备。
这个库不依赖单一信号,而是组合了五类浏览器特征:
- 语言信息:
navigator.language与navigator.languages - 时区信息:
Intl.DateTimeFormat().resolvedOptions().timeZone - 设备特征:通过 Emoji 渲染差异做一个轻量探测
- 字体信息:检测浏览器可用的常见中文字体
- 网络特征:通过部分网络可达性探测判断当前网络出口(异步,可选)
安装
npm i is-china-user使用
import { isChinaUser } from "is-china-user";
// 中国用户
isChinaUser(); // true
// 中国大陆用户
isChinaUser({ mainland: true }); // true如何避免被判断为中国用户
- 修改浏览器语言,避免含有中文
- 修改操作系统语言,避免含有中文
- 修改操作系统时区,选中国相邻的国家和地区(如果选西方有可能根据访问时间和时区内平均时间不一致反而被标记)
- 使用纯英文操作系统,避免系统字体库有特定中文字体,如仿宋、等线等
- 避免无法显示某些特殊 Emoji,这个最麻烦因为很多情况下跟随设备无法更改,需要修改相关操作系统配置文件。
这里不包括 IP 地址, 以上的前提都是 IP 地址干净的情况下的额外措施。
API
isChinaUser()
综合判断当前用户是否更像中国用户。
它会把语言、时区、Emoji 设备特征、中文字体四类信号做组合判断,只要任意一个信号为正,就返回 true。
isChinaByLanguage(options?)
判断当前语言设置是否为中文。
默认规则:
navigator.languages中只要任意一项是中文,就返回true
可选参数:
isChinaByLanguage({
mainland?: boolean;
strict?: boolean;
});mainland: true时,只接受更偏向中国大陆简体环境的语言写法,例如zh-CN、zh-Hansstrict: true时,只检查首选语言navigator.languages[0]
示例:
isChinaByLanguage(); // 宽松判断
isChinaByLanguage({ strict: true }); // 只看首选语言
isChinaByLanguage({ mainland: true }); // 只认大陆简体倾向isChinaByTimeZone(options?)
判断时区是否在中国相关时区内。
可选参数:
isChinaByTimeZone({
mainland?: boolean;
strict?: boolean;
});- 默认会把大陆和港澳台常见时区都视作正向信号
mainland: true时,只认大陆常见时区- 如果无法读取
Intl时区,会退回到getTimezoneOffset(),以UTC+8作为备选判断 strict:true时不会退回UTC+8而必须是已知时区
isChinaByEmoji()
通过 Emoji 渲染差异判断设备特征。
内部会先用 😀 做对照:只有设备能正常彩色渲染普通 Emoji、却无法彩色渲染 🇹🇼 时才判定命中,避免在缺少彩色 Emoji 字体的环境(如部分 Linux)或开启 canvas 指纹保护的浏览器上误报。
- 返回
true表示更像中国大陆设备 - 返回
false表示未命中 - 返回
null表示无法判断(Windows、无 DOM 环境、设备不支持彩色 Emoji 渲染等)
isChinaByFont(options?)
检测浏览器是否能使用常见中文字体,例如 DengXian、FangSong 等。
可选参数:
isChinaByFont({
fontList?: string[];
});fontList用来覆盖默认字体列表适合你想针对特定字体集合做检测,或者在自己的业务里做更细的环境探测
返回
true表示检测到常见中文字体返回
false表示未命中,或当前环境不支持 canvas 检测
示例:
isChinaByFont();
isChinaByFont({
fontList: ["HarmonyOS Sans"],
});isChinaByNetwork(options?)
异步方法,通过网络可达性判断当前网络出口是否在中国大陆。由于要加载远程探针图片,不会默认使用, 如果有需要手动使用。
原理:同时加载大陆通常无法访问的探针图片(默认包含 https://www.gstatic.com/images/branding/searchlogo/ico/favicon.ico、https://chatgpt.com/favicon.ico)和大陆可达的对照图片(默认包含 https://www.baidu.com/favicon.ico):
- 探针可达 → 返回
false(不在大陆网络,或已走代理) - 探针不可达但对照可达 → 返回
true - 两者都不可达 → 返回
null(可能离线或被扩展拦截,无法判断)
const result = await isChinaByNetwork({ timeout: 3000 });也可以传入自定义探针,并通过 detail: true 获取每个探针的可达性:
const detail = await isChinaByNetwork({
timeout: 3000,
detail: true,
probes: {
noChina: ["https://example.com/blocked-in-mainland.png"],
global: ["https://example.com/reachable-everywhere.png"],
},
});
// detail.result: boolean | null
// detail.probes: { type: "noChina" | "global"; url: string; reachable: boolean }[]与其它几个设备侧信号不同,这个方法反映的是当前网络出口,更接近服务端实际看到的用户位置——如果你想知道某个网站/API 会不会把你当成中国用户,这是权重最高的信号。
注意:会产生真实图片加载请求,且结果受代理/VPN 影响(这正是它的用途)。默认的 isChinaUser() 是同步方法,不包含此检测,需要单独调用
推荐用法
如果你只想快速分流:
if (isChinaUser()) {
// show China-specific content
}如果你想更可控:
const isCNLang = isChinaByLanguage({ strict: true });
const isCST = isChinaByTimeZone();
const isEmojiMatch = isChinaByEmoji();
const isFontMatch = isChinaByFont({
fontList: ["方正黑体"],
});
console.log({ isCNLang, isCST, isEmojiMatch, isFontMatch });说明
- 这个库是浏览器侧判断,不建议在 Node.js 里直接调用
isChinaByEmoji() isChinaUser()偏向“尽量识别”,不是法律意义或身份意义上的严格归类- 如果要仅识别中国大陆用户,需要使用
{ mainland: true }参数
