目标: 搭建一个XMPP服务器, 实现在web page上用javascript与自己XMPP服务器通信, 匿名登录并与任何一个XMPP(Jabber)帐户通信. (Gtalk目前尚有问题)
XMPP服务器可能不是必须的(见下文, 我没有尝试)
环境与配置:
XMPP服务器:ejabberd文档
HTTP-Binding: 使用ejabberd搭建, 5280端口.
Javascript Client:Strophe文档
安装Ejabberd
-
yum
installejabberd
-
#apt-get install ejabberd
编辑配置文件: /etc/ejabberd/ejabberd.cfg, 这是个era lang格式配置文件, 行注释符号是%. 请参考ejabberd文档.
下面是默认配置文件里我修改过部分:
%%debug
{loglevel, 5}.
{hosts, ["sagan.me"]}.
{host_config, "sagan.me", [{auth_method, [anonymous,internal]},{anonymous_protocol, sasl_anon}]}.
{listen,
[
{5222, ejabberd_c2s, [
{certfile, "/path/to/ssl/cert.pem"},
%%starttls,
starttls_required,
{access, c2s},
{shaper, c2s_shaper},
{max_stanza_size, 65536}
]},
{5269, ejabberd_s2s_in, [
{shaper, s2s_shaper},
{max_stanza_size, 131072}
]},
{{5280, "127.0.0.1"}, ejabberd_http, [
{request_handlers, [{["http-bind"], mod_http_bind}]},
captcha
]}
]}.
{s2s_use_starttls, true}.
{s2s_certfile, "/path/to/ssl/cert.pem"}.
{s2s_default_policy, allow}.
{auth_method, [internal, anonymous]}.
上面配置中, 声明监听127.0.0.1(本地IP地址) 5280端口为http-binding (BOSH)服务地址, 路径是"http-bind", 即服务实际URI是"http://127.0.0.1:5280/http-bind". 然后需要在web服务器配置中用mod_proxy或mod_rewrite将80或443端口上对 "/http-bind" 访问转发到"http://127.0.0.1:5280/http-bind", 因为由于浏览器同源限制, yourdomain.com:80上的web page是无法直接向yourdomain.tld:5280提交ajax请求的. ( 所以在上面配置中把ejabberd http-bind监听的端口设为了127.0.0.1:5280, 即不能从外部直接访问)
添加域名DNS SRV记录
这一步是必须的, 否则搭建的XMPP服务器基本上无法与大多数其它服务器或客户端通信. (插一句: Google Apps Talk基于XMPP平台, 如果不设置域名SRV记录的话, 就只能够用Gtalk登录(无法使用其它XMPP客户端), 而且只能和gmail.com或其它Google Apps域名的帐户通信)
_xmpp-client._tcp.sagan.me. 86400 IN SRV 10 0 5222 sagan.me.
_xmpp-server._tcp.sagan.me. 86400 IN SRV 10 0 5269 sagan.me.
5269和5222是XMPP在ICANN注册的标准端口.
修改WEB服务器配置
我的Lighttpd ModProxy配置:
proxy.server = (
"/http-bind" => ( (
"host" => "127.0.0.1",
"port" => 5280
) )
)
应该也可以用web服务器直接转发请求到外部某个公开的Jabber (XMPP)服务器 http-bind地址, 我没有尝试. (基本上找不到公开的提供http-bind的XMPP服务器)
使用Javascript客户端
上面ejabberd配置里开启了匿名登录(ANOYMOUS mechanism), 最终目的就是为了在web page中匿名访问服务并向任何一个XMPP帐户发送消息.
下载Strophe JS库并上传到你的域名目录下(这个库只有一个文件strophe.js), 下面这个测试例子修改自Strophe examples目录下echobot.html
-
-
-
-
Strophe.js Echobot Example
-
-
-
-
-
-
-
-
-
-
看echobot.js
-
varBOSH_SERVICE =
'/xmpp-httpbind';
-
varconnection =
null;
-
-
functionlog
(msg
)
-
{
-
$
(
'#log'
).
append
(
''
).
append
(document.
createTextNode
(msg
)
);
-
}
-
-
functiononConnect
(
status
)
-
{
-
if
(
status== Strophe.
Status.
CONNECTING
)
{
-
log
(
'Strophe is connecting.'
);
-
}
else
if
(
status== Strophe.
Status.
CONNFAIL
)
{
-
log
(
'Strophe failed to connect.'
);
-
$
(
'#connect'
).
get
(
0
).
value=
'connect';
-
}
else
if
(
status== Strophe.
Status.
DISCONNECTING
)
{
-
log
(
'Strophe is disconnecting.'
);
-
}
else
if
(
status== Strophe.
Status.
DISCONNECTED
)
{
-
log
(
'Strophe is disconnected.'
);
-
$
(
'#connect'
).
get
(
0
).
value=
'connect';
-
}
else
if
(
status== Strophe.
Status.
CONNECTED
)
{
-
log
(
'Strophe is connected.'
);
-
log
(
'ECHOBOT: Send a message to '+ connection.
jid+
-
' to talk to me.'
);
-
-
connection.
addHandler
(onMessage,
null,
'message',
null,
null,
null
);
-
connection.
send
($pres
(
).
tree
(
)
);
-
varreply = $msg
(
{to:
"[email protected]", from: connection.
jid, type:
'chat'
}
).
c
(
"body"
).
t
(
"Test Chat Message"
);
-
connection.
send
(reply.
tree
(
)
);
-
}
-
}
-
-
functiononMessage
(msg
)
{
-
varto = msg.
getAttribute
(
'to'
);
-
varfrom = msg.
getAttribute
(
'from'
);
-
vartype = msg.
getAttribute
(
'type'
);
-
varelems = msg.
getElementsByTagName
(
'body'
);
-
-
if
(type ==
"chat"
&&elems.
length
>
0
)
{
-
varbody = elems
[
0
];
-
-
log
(
'ECHOBOT: I got a message from '+ from +
': '+
-
Strophe.
getText
(body
)
);
-
-
varreply = $msg
(
{to: from, from: to, type:
'chat'
}
)
-
.
cnode
(Strophe.
copyElement
(body
)
);
-
connection.
send
(reply.
tree
(
)
);
-
-
log
(
'ECHOBOT: I sent '+ from +
': '+ Strophe.
getText
(body
)
);
-
}
-
-
// we must return true to keep the handler alive.
-
// returning false would remove it after it finishes.
-
return
true;
-
}
-
-
$
(document
).
ready
(
function
(
)
{
-
connection =
newStrophe.
Connection
(BOSH_SERVICE
);
-
-
// Uncomment the following lines to spy on the wire traffic.
-
//connection.rawInput = function (data) { log('RECV: ' + data); };
-
//connection.rawOutput = function (data) { log('SEND: ' + data); };
-
-
// Uncomment the following line to see all the debug output.
-
//Strophe.log = function (level, msg) { log('LOG: ' + msg); };
-
-
-
$
(
'#connect'
).
bind
(
'click',
function
(
)
{
-
varbutton = $
(
'#connect'
).
get
(
0
);
-
if
(button.
value==
'connect'
)
{
-
button.
value=
'disconnect';
-
-
connection.
connect
($
(
'#jid'
).
get
(
0
).
value,
-
$
(
'#pass'
).
get
(
0
).
value,
-
onConnect
);
-
}
else
{
-
button.
value=
'connect';
-
connection.
disconnect
(
);
-
}
-
}
);
-
}
);
将[email protected]修改为一个测试Jabber帐号. 然后用浏览器打开echobot.html, 点击Connect按钮, Strophe就会匿名登录到刚刚建立的ejabber服务器( sagan.me ), 并向 "[email protected]"这个帐号发送一条"Test Message"的信息.
另: 测试匿名登录向[email protected] 发送消息失败, log里显示Gtalk服务器返回信息是503 error, Service-Unavailable, 但如果正常登录并添加Gtalk为好友的话则可以. Gtalk禁止了匿名用户向其发送消息? 我还在查资料中.
我准备用Javascript写一个简单的XMPP WEB匿名客户端, 实现允许访客直接与Gtalk和Facebook Chat通信等功能.