闲聊几句
大概是一年前,我就已经了解过这款产品。当时也有过建站,但是没有坚持下来。现在是第二次尝试。在原先的基础上,增加了更多的自定义。在这里记录一下网站接入闲聊么的过程。
简单接入
xianliao.me是支持最简洁的方式接入到你的网站的,只需要在他们的官网注册一个账号。你就能得到一个web_id和SSO_key。
根据上面的图片,只需要使用很简单的代码,就可以接入到你的网站。
但是,有一个非常现实的问题,如果访问者想要加入,必须使用微信扫一扫才能登录并且开始聊天。
相信不是流量特别大的网站,这一步应该可以劝退一大波的访问者了。所以就有了下文。我是如何通过他的API搭建起一个只需要输入一个随机用户名就能开始聊天的系统的。
分析API
在xianliaome的官网,我们发现他们提供了 定制代码接入 的功能,我们可以通过手机端接入API,模拟出一个“已登录用户”,提供给游客进行聊天。
在手机端接入闲聊么的方法:
https://xianliao.me/s/你的web_id?mobile=1&uid={登录用户的ID}&username={登录用户的用户名,需要做URI encode}&avatar={登录用户的头像URL,需要做URI encode}&ts={当前的Linux timestamp}&token={即xlm_hash,见下附的xlm_hash的生成方法}
通过上面的接口信息我们可以看出来,其中登录用户id,用户名,用户头像我们都可以通过一个特定规则进行模拟。然后得到一个完整的模拟用户,提供给闲聊么,然后他会返回一个完整的聊天窗口给我们。
模拟用户
用户id
首先要声明的是,经过我的测试,同一个web_id下,用户ID是不能够重复的,重复就会当做同一个用户,所以,我们需要采用一套不会重复或者重复几率较小的生成规则生成用户ID。
我们生成随机数的时候,使用9301, 49297, 233280三个数字作为基数(原理看这儿:https://www.zhihu.com/question/22818104), 生成一个理论上不会重复的用户ID。
用户名
用户名,我们可以通过弹框让访问的游客自己输入一个名称,也可以使用随机生成一个姓名。此处无太多技术点,不做详解。
用户头像
如果不传头像,“闲聊么”会用一个空白作为默认头像,但是不够美观,所以在这里,我们使用 http://www.gravatar.com 。
使用gravatar后,我们只需要一个简单的http请求,就能够获得一个有趣的头像。
http://www.gravatar.com/avatar/{hash}?s=256&d=identicon
- hash: 生成一个随机数填充
- s:尺寸
- d:风格,目前可选 identicon、monsterid、wavatar、retro、robohash 等。具体可见官方文档
hash的话,我们前面生成了一个可能不会重复的user_id,在这里,就可以将user_id当做hash传入到请求中。
s,尺寸,可以不用传,默认尺寸即可。
d,风格,我使用了数组保存了五种风格,然后每次创建用户的时候使用一个[0-4]的随机数,使用随机数当做styleArray的下标获得一个随机的风格。
生成chat_url
有了上面的几步,我们获得了web_id,sso_key,user_id,username,avatar。timestamp可以获取。现在,我们已经能够生成一个token了。
create token
按照官方文档,token的生成是由以下几个字段经过SHA512加密之后的字符串。
webid_userid_当前时间戳_ssokey
由于SSO_KEY属于隐私信息,所以我们不能够在前端生成token,这一步,应该交给后台。
后端编写一个**createXianLiaoToken()**接口,前台传入当前时间戳和用户ID即可,web_id和SSO_KEY保存在服务端。
此处,我使用Java演示。
Controller.java
/**
* 用于生成闲聊么 所需要的token信息
*/
@GetMapping("createXianLiaoToken")
public @ResponseBody String createXianLiaoToken(HttpServletRequest request) {
String uid = request.getParameter("uid");
String timestamp = request.getParameter("timestamp");
String str = WebConst.WEB_ID + "_" + uid + "_" + timestamp + "_" + WebConst.SSO_KEY;
try {
return Commons.SHA(str, "SHA-512");
} catch (Exception e) {
throw new TipException("系统异常, SHA-512加密失败.");
}
}
Commons#SHA(网上很多,我在CSDN复制的)
public static String SHA(final String strText, final String strType) {
// 返回值
String strResult = null;
// 是否是有效字符串
if (strText != null && strText.length() > 0) {
try {
// SHA 加密开始
// 创建加密对象 并傳入加密類型
MessageDigest messageDigest = MessageDigest
.getInstance(strType);
// 传入要加密的字符串
messageDigest.update(strText.getBytes());
// 得到 byte 類型结果
byte byteBuffer[] = messageDigest.digest();
// 將 byte 轉換爲 string
StringBuffer strHexString = new StringBuffer();
大专栏 闲聊么 // 遍歷 byte buffer
for (int i = 0; i < byteBuffer.length; i++) {
String hex = Integer.toHexString(0xff & byteBuffer[i]);
if (hex.length() == 1) {
strHexString.append('0');
}
strHexString.append(hex);
}
// 得到返回結果
strResult = strHexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
return strResult;
}
AJAX
// 从后台获取到与闲聊么通信的token
function getToken(xlm_uid, timestamp) {
var result = null;
$.ajax({
url: [[@{/createXianLiaoToken}]],
type: 'GET',
dataType: 'text',
contentType: 'application/json',
data: {'uid': xlm_uid, 'timestamp': timestamp},
async: false,
success: function(data){
result = data;
}
});
return result;
}
通过上述操作,我们拿到了token,然后我们可以开始组装整个chat_url信息。
根据官网的文档,chat_url的格式为:
https://xianliao.me/s/web_id?mobile=1&uid={登录用户的ID}&username={登录用户的用户名,需要做URI encode}&avatar={登录用户的头像URL,需要做URI encode}&ts={当前的Linux timestamp}&token={即xlm_hash,见下附的xlm_hash的生成方法}
我们将上面步骤获得信息,一一填入到链接中,然后通过window.location.href = chat_url,将当前页面重定向到闲聊么的页面。就得到了一个闲聊么的聊天界面了。下面看一下我的完整前端代码。
xianliaome.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>闲聊么</title>
<script th:src="@{//cdn.bootcss.com/jquery/2.2.3/jquery.min.js}"></script>
</head>
<body>
<script th:inline="javascript">
// thymeleaf 不能输入地址符,但是闲聊么api又不能识别转移后了的&,所以用CDATA包起来.
/*<![CDATA[*/
var ds = ['identicon', 'monsterid', 'wavatar', 'retro', 'robohash'];
// 初始化闲聊么需要的数据
function init() {
var web_id = 'xxxxxx';
var xlm_uid;
var xlm_name;
var xlm_avatar;
if (easyLocalStorage('xlm_uid') != null) {
xlm_uid = easyLocalStorage('xlm_uid');
xlm_name = easyLocalStorage('xlm_name');
xlm_avatar = easyLocalStorage('xlm_avatar');
}else {
xlm_uid = decodeURI(Math.seededRandom(Date.parse(new Date()), 1));
var name = prompt('请输入用户名').trim();
xlm_name = decodeURI(name === '' ? '匿名' : name);
xlm_avatar = decodeURI(avatarRandom(xlm_uid));
easyLocalStorage('xlm_uid', xlm_uid);
easyLocalStorage('xlm_name', xlm_name);
easyLocalStorage('xlm_avatar', xlm_avatar);
}
var timestamp = Date.parse(new Date());
var token = getToken(xlm_uid, timestamp);
window.location.href = "https://www.xianliao.me/s/" + web_id + "" +
"?mobile=1" +
"&uid=" + xlm_uid + "" +
"&username=" + xlm_name + "" +
"&avatar=" + xlm_avatar + "" +
"&ts=" + timestamp + "" +
"&token=" + token;
}
$(function () {
init()
})
// 从后台获取到与闲聊么通信的token
function getToken(xlm_uid, timestamp) {
var result = null;
$.ajax({
url: [[@{/createXianLiaoToken}]],
type: 'GET',
dataType: 'text',
contentType: 'application/json',
data: {'uid': xlm_uid, 'timestamp': timestamp},
async: false,
success: function(data){
result = data;
}
});
return result;
}
// 通过gravatar.com.随机获取一个有趣的用户头像
function avatarRandom(xlm_uid) {
var num = Math.floor(Math.random() * 4 + 1);
return 'http://www.gravatar.com/avatar/' + xlm_uid + '?d=' + ds[num];
}
// 对本地存储的建议封装
function easyLocalStorage(key, value) {
if (value == null || value.trim() === '') {
return localStorage.getItem(key);
}else {
localStorage.setItem(key, value);
}
return true;
}
// 获取一个随机数
Math.seed = 5;
Math.seededRandom = function(max, min) {
max = max || 1;
min = min || 0;
Math.seed = (Math.seed * 9301 + 49297) % 233280;
var rnd = Math.seed / 233280.0;
return Math.ceil( min + rnd * (max - min) ); // Math.ceil实现取整功能,可以根据需要取消取整
};
/*]]>*/
</script>
</body>
</html>
如何使用
上面的教程,我们已经有了一个xianliaome.html的页面,在我们需要使用的地方,我们可以通过iframe将其嵌入到当前页面中。
至此,就完成了我们闲聊么的匿名聊天功能了。
缺陷
- 闲聊么的页面还有一点问题,会挡住我们自己的页面。
- 如果需要访客输入用户名的话,那么尽管没有点击聊天,打开页面就会弹出输入用户名的弹框,非常不友好
正对上面的不足,我将会继续优化。直至完美。
感谢阅读,第一次写长篇博客,排版和描述不是特别友好。