Appearance
接入问题排查
按你看到的现象往下找。排查前先打开浏览器开发者工具的控制台和网络面板,多数问题在那里有直接线索。
网站上没有出现咨询入口
可能原因与解决办法
| 检查 | 怎么确认 | 解决 |
|---|---|---|
| 代码没加载 | 网络面板搜 hecong.js 看是否 200 | 确认贴在每页 </body> 前,且已重新发布 |
| 脚本地址不对 | 看 src 对不对 | 被改过会 404,见下 |
| 渠道 ID 没填 | 控制台提示缺 data-channel-id | 从工作台 安装代码 重新复制完整代码 |
| 渠道被停用 | 控制台提示 Channel unavailable | 在 设置 > 渠道管理 > 基本信息 里打开状态开关 |
| 内容安全策略拦截 | 控制台出现 CSP 违规提示 | 参见接入代码与配置项的 CSP 章节放行域名 |
| 广告插件屏蔽 | 停用浏览器扩展后重试 | 客户浏览器的个例,无需处理 |
| 浏览器版本过低 | 换一台设备或换个浏览器打开同一个地址 | 见浏览器兼容性 |
脚本地址应为 https://assets.aihecong.com/sdk/hecong.js。
咨询入口不出现,控制台提示 Request denied
这是什么:你的网站域名不在渠道的授权域名里,或者 data-channel-id 填的渠道不存在。聊天窗要先取渠道配置才能画出入口,这一步就被拒掉了(网络面板里 /sdk/config 返回 401),所以页面上什么都不出现。控制台里的原文是:
[hecong] Request denied: add this site's domain to the channel's allowed domains, or check data-channel-id授权域名留空时不做限制,出现这个错说明已经填过内容了。
解决:先确认 data-channel-id 是从工作台 安装代码 里完整复制的。域名的问题在工作台 设置 > 渠道管理 > 安全与隐私 中把你的域名加进去。本地开发填 localhost(不带端口),子域用 *.example.com(它不含裸域名,example.com 要另填一条),详见接入代码与配置项。
错误:/sdk/config 返回 400
这是什么:data-channel-id 不是一个完整的渠道 ID,格式就没通过,多半是复制时被截断了。控制台里的提示和上一条相同([hecong] Request denied: ...),两者都从渠道 ID 查起。这一条只针对取渠道配置的接口;identify() 返回的 400 见下一条。
解决:确认 data-channel-id 是从工作台安装代码里完整复制的,没有多余的空格或换行。
错误:web_sdk_identify_user_id_placeholder
这是什么:identify() 传的客户 ID 是一个占位值,被拒绝了,请求返回 400。guest、test、0、undefined、null 这类值都会被拒绝。多半是代码里这两种情况:访客没登录时给了个默认值,或者对接期的测试代码上了线。拦的就是这个:这类值一旦放行,所有拿到它的访客会被认成同一个人,聊天记录互相可见。
解决:拿不到真实客户 ID 时,整个 identify() 不要调,那样就是匿名访客,客服照常接待。取值要求见传客户资料给客服。
错误:WebSdkConfigError
这是什么:聊天窗找不到会话凭证端点。
解决:用工作台生成的接入代码不会遇到这个问题 —— 服务端地址已经内置在脚本里。出现这个报错说明 src 被改动过或用的不是官方脚本,从工作台 安装代码 重新复制一遍。私有化部署的地址在构建时烘焙,同样不需要你在页面上配。
错误:window.hecong is not a function
这是什么:接入脚本带 async 异步加载,你的内联代码先于它执行,此时 window.hecong 还不存在。本地或有缓存时脚本加载快,可能碰巧不报错,到了线上真实网络就变成时有时无的报错。
解决:在第一次调用之前补上一行占位函数(照原样复制,不要改写):
js
window.hecong = window.hecong || function (c) { (window.hecong.q = window.hecong.q || []).push(c) }有了它 window.hecong 从一开始就存在,早调的回调排队等脚本就绪。完整说明见接入代码与配置项。
点自己的按钮没反应,控制台提示 Use hecong(api => api.open())
这是什么:打开聊天窗的代码写成了 window.hecong.show() 或 window.hecong.open()。window.hecong 是一个函数,命令要放在它的回调里执行,写成属性调用不会做任何事。控制台里的原文是:
[hecong] Use hecong(api => api.open()), not hecong.show()解决:改成把命令放进回调:
js
window.hecong(function (hc) { hc.open() })全部可用命令见接口速查。
错误:document is not defined
这是什么:聊天窗依赖浏览器环境,在服务端渲染阶段执行了初始化代码。
解决:把初始化放进仅客户端执行的生命周期。Next.js / Nuxt 的写法参见接入代码与配置项的服务端渲染章节。
调了 identify 但客服看不到用户信息
排查顺序
先在网址后面加 ?hcdebug=1 打开调试模式,面板会直接给出结论:传了什么、写进去几项、哪一项被丢了。面板给不出结论时再按下面逐条查。
- 确认代码执行了 —— 在回调里加
console.log,看是否走到 - 确认
id不为空、也不是占位值 —— 空字符串和guest、test这类值都会被拒绝,见上面web_sdk_identify_user_id_placeholder - 查看哪些字段生效了 —— 先把聊天窗点开再执行下面的调试代码(客户没点开聊天窗时
identify的 Promise 不会返回,await会一直等下去,见传客户资料给客服),返回值的acceptedKeys列出实际写入的字段:
js
const result = await hc.identify({
id: 'c9a1f0e2-7b34-4d58-9f61-0ab2d3c4e5f6',
data: { level: 'gold' }
})
console.log('实际写入的字段:', result.acceptedKeys)不在 acceptedKeys 里的字段说明未在工作台定义。前往 设置 > 客户字段 添加后重试。
同一位客户被识别成了多个客户
这是什么:传给 identify 的 id 取值不稳定,每次进来都被当作新客户。
解决:确认传的是数据库 UUID 这类永不变更、且外人猜不到的值。每次登录重新生成的会话 ID 就属于不稳定的取值;手机号、邮箱虽然稳定,但外人猜得到、客户也可能更换。取值要求见传客户资料给客服。
同一位客户在两台设备上同时聊,消息没有实时同步
这是什么:同一位客户在电脑和手机上同时开着聊天窗,客服那边会看到两条并行的对话。客服的回复只在其中一台上实时弹出,另一台要刷新才看到 —— 消息不会丢,刷新后两台看到的是同一份完整记录。
同一台设备上开多个标签页不受影响,标签页之间是实时同步的。这里说的只是两台不同设备同时在线。
解决:刷新没收到消息的那台设备,就能看到完整记录。
同一位客户每次来都是新访客
这是什么:没调 identify() 时,合从靠存在客户浏览器里的一个本地标识认人。客户清了浏览器数据、用无痕模式、换了设备或浏览器,这个标识就没了,系统只能当成新访客。
无痕模式还有一层:浏览器可能整个禁止网页写本地存储,此时标识连当次会话都存不住,关掉标签页就没了。
解决:有登录体系的话调 identify() 传一个稳定的客户 ID,按 ID 认人,换设备也能接上同一段历史。没有登录体系的话这是浏览器机制决定的,改不了。
客户看不到麦克风按钮
这是什么:工作台里语音消息是开的,客户的聊天窗里却没有麦克风按钮,也没有任何报错。
排查顺序
| 检查 | 怎么确认 | 解决 |
|---|---|---|
| 配置档位 | 聊天窗口 的「语音消息」 | 默认「仅手机」,电脑上要录改成「全部开启」 |
| 网站不是 HTTPS | 看地址栏是不是 http:// 开头 | 换成 HTTPS,见下 |
| 浏览器不支持 | 换 Chrome 或 Safari 试 | Firefox 全版本录不了,见浏览器兼容性 |
浏览器只允许安全网页调用麦克风。localhost 调试不受影响,所以本地正常、线上没有,基本就是网站还在 HTTP 上。
客户点了麦克风提示没有权限
这是什么:按钮在,客户按下去弹出「没有麦克风权限」之类的提示。这是客户自己拒绝过授权,或者系统层面禁掉了浏览器的麦克风。
解决:让客户点浏览器地址栏左侧的权限图标(锁形或滑块图标),把麦克风改成允许,然后刷新页面。手机上则在系统设置里找到浏览器 App,打开麦克风权限。
排查时注意区分另外两种情况:设备上根本没有麦克风、麦克风被其他软件独占(会议、录屏工具),这两种客户会看到不同的提示。
微信里点下载没有反应
这是什么:客户在微信内置浏览器或小程序里打开你的页面,点聊天窗里的文件下载,没有任何反应。
微信拦掉了网页发起的文件下载,这一层不是合从能绕过的。聊天窗检测到微信环境后会降级成给出链接让客户复制,而不是直接下载。
解决:让客户按提示复制链接,用系统浏览器打开下载。
有新消息但没有提示音
这是什么:浏览器不允许网页在客户没跟页面交互过的情况下播放声音,这是浏览器为了拦广告噪音统一做的限制。客户打开页面后一次都没点过,第一条消息的提示音就会被拦掉。
客户点开聊天窗就已经算交互了,所以正常咨询流程里很少遇到;真遇到时红点和气泡照常显示,不影响他看到消息。
解决:不需要处理,客户与页面产生一次交互之后就恢复正常。
手机上聊天按钮和聊天窗都很小
这是什么:你的页面没有声明移动端视口。缺这个声明时,手机浏览器会把整个页面当成宽 980 像素的电脑网页渲染再缩小显示,按钮小到不好点,聊天窗里的字也跟着变小。
解决:在页面的 <head> 里加上这一行,你网站自身在手机上的显示效果也会一并改善:
html
<meta name="viewport" content="width=device-width, initial-scale=1" />合从不会替你改这个标签 —— 它影响的是你整站在手机上的渲染,而且它在页面刚解析时就要生效,聊天窗加载起来时再改已经晚了。
全面屏手机上输入框紧贴屏幕最底部
这是什么:全面屏手机屏幕最下方那条半透明的手势横条,聊天窗的输入区紧挨着它,看着局促。微信、企业微信这类 App 内置的网页里最明显。
解决:在页面的 viewport meta 里加上 viewport-fit=cover,聊天窗就会自动留出手势条的高度:
html
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />不加也能正常收发消息,只是输入区贴着屏幕底边。如果你的页面顶部有固定定位的导航栏,加上之后它会延伸到状态栏区域,自己留出间距即可。
聊天窗样式和网站冲突
聊天窗在 Shadow DOM 内渲染,样式与页面互相隔离,正常情况下不会冲突。
如果确实出现异常,检查页面上是否有针对 * 的全局样式规则,或对所有元素设置了 !important 的 CSS 重置——这类规则可能穿透进 Shadow DOM 边界。
单页应用里事件重复触发
这是什么:路由切换时重复注册了监听器,没有清理旧的。
解决:on() 与 registerComposerAction() 都返回注销函数,在组件卸载时调用:
jsx
useEffect(() => {
let off
let cancelled = false
window.hecong(hc => {
if (cancelled) return
off = hc.on('user:identified', handler)
})
return () => {
cancelled = true
off?.()
}
}, [])组件在聊天窗脚本就绪前卸载时 off 还没拿到,cancelled 让迟到的回调不再注册,详见 React 与 Vue 接入示例。
还是没解决
把以下信息提供给合从技术支持,能大幅缩短定位时间:
- 出问题的页面地址
- 浏览器控制台的完整报错
- 网络面板里失败请求的地址与状态码
- 渠道名称(不需要提供渠道 ID)