本站教程关于socket部分有一些同学反馈和听天书一样迷蒙,而对我们多数项目来说,socket很大一部分需求是发起HTTP请求读网页API,为方便使用,最新的mudcore框架中封装了HTTP客户端模块,使用这个模块,发起HTTP请求变得非常容易。
模块代码:https://github.com/mudcore/mudcore/blob/master/inherit/Http.c
如果你的项目没有引入mudcore框架,可以直接复制此代码到你的项目中使用。
重要提示
最新版fluffos已完善对external_start的支持,在MUD中处理HTTP的方案除了自己通过socket模拟,现在还可以直接调用curl指令,推荐使用调用curl方式,因为自己用socket实现http请求是要完全的熟悉http协议并自己实现所有细节功能,而使用curl你完全不用关心http协议的细节,只要会用curl并对结果处理就好,更简单强大,具体介绍可参考:https://bbs.mud.ren/threads/244
当然能用curl并不代表以下内容没有意义,毕竟curl对不支持external_start函数的驱动就不能用了,而socket是基础,包括mudos等所有驱动都支持,兼容性更高,对基础的http使用socket效率也更高,代码也更灵活可控,任何复杂功能都可以自己实现。比如:
使用说明
对需要请求HTTP的文件直接继承Http模块:
inherit CORE_HTTP;
然后可使用Http模块封装好的几个方法:
varargs object get(string url, mapping query, mapping header);
varargs object post(string url, mixed body, mapping header);
varargs object head(string url, mapping query, mapping header)
varargs object ws(string url, mapping query, mapping header);
注意:CORE_HTTP支持HTTPS,但这个需要fluffos驱动支持,如果需要用到https,请更新fluffos到最新版。
请求数据(request)
目前只实现了最基础的get和post请求,可以满足目前所有基础需求,其它方法还没有实现,将来会根据项目需求和大家的反馈完善功能。
提示:HTTP请求第一次因为DNS查询会比较慢,但查询成功后的域名和IP会缓存下来,再次请求就会很快了。
注意:目前HTTP模块虽然发的是HTTP/1.1协议,其实只是使用了host域名相关,并没有使用长连接,除了websocket模式外,和服务器的连接外并不是持久连接,通信结束自动关闭了连接。
GET请求
get请求使用非常简单,直接Http::get(url);即可,对请求的参数即可以直接传在url中,如:
Http::get("http://mud.ren/path?key1=value1&key2=value2");
也可以以映射的方式传在第二个参数中,如:
Http::get("http://mud.ren/path", (["key1":"value1", "key2":"value2"]));
如果需要传header,请以映射的方式传第三个参数,如:
Http::get(Url, (["content":tpl, "mobile":mobile]), (["Content-Type":"application/json;charset=UTF-8", "X-Bce-Signature":"AppCode/" + AppCode]));
POST请求
post请示和get请求类似,唯一的区别是第二个参数是post的body,参数可以是映射,也可以是raw格式的字符串。如:
varargs void send(string msg, int qun)
{
string body;
string qq_qun = Group + "";
if (qun)
{
qq_qun = qun + "";
}
// body字符串,注意转义
// body = "{\"sessionKey\":\"" + Session + "\",\"target\":" + qq_qun + ",\"messageChain\":[{\"type\":\"Plain\",\"text\":\"" + msg + "\"}]}";
// 美化格式,不用转义
body = @RAW
{
"sessionKey": "%^session%^",
"target": %^group%^,
"messageChain": [
{
"type": "Plain",
"text": "%^msg%^"
}
]
}
RAW;
body = terminal_colour(body, ([
"session":Session,
"group":qq_qun,
"msg":msg,
]));
Http::post(Base_uri + "/sendGroupMessage", body);
}
WS协议
websocket部分只是实现了连接和接收消息,比如在MUD中接收QQ群的消息,未实现发送数据功能,这里不做说明,具体可参考mudcore框架的示例代码/system/daemons/http/qq_d.c。
响应(response)
客户端发求请求后要等服务端响应后处理,在MUD中对响应数据的处理只需要实现reponse()方法即可。
protected void response(mixed result)
{
// 你对响应数据result的处理
}
Http模块会在收到响应后自动关闭socket连接,但如果响应是分包传输,可以重写receive_data()方法自己处理,如:
// 分包传输(transfer-encoding: chunked)处理
protected void receive_data(int fd, mixed result)
{
response(result);
if (strsrch(result, "\r\n0\r\n") > 1)
{
socket_shutdown(fd);
}
}
调试
如果在发起请求后没有正常的响应,可以在发起请求前把全局变量Debug赋值为1开启调试模式,相关内容会输出到控制台debug.log日志中。如:
void get(string url)
{
Debug = 1;
Http::get(url);
}
以下是一个完整的Http请求示例:
inherit CORE_HTTP;
nosave string Url = "http://api.oiuv.cn/api/mobile/";
nosave object Receiver;
protected void response(mixed result)
{
mixed *status = allocate(3);
sscanf(result, "%s %d %s\r\n", status[0], status[1], status[2]);
if (status[1] == 200)
{
mixed res = json_decode(trim(result[strsrch(result, "{")..]));
tell_object(Receiver, sprintf("%O", res));
}
}
void query(object me, int mobile)
{
Receiver = me;
Http::get(Url + mobile);
}
这是一个手机号码查吉凶的娱乐功能,使用Http模块后,直接实现一个query()方法请求数据,通过reponse()方法把结果发到聊天中,而需要使用时直接调用请求即可,如:MOBILE_D->query(me, 13800138000);
更多示例请看mudcore框架/system/daemons/http/下的代码。
关于长连接
当前模块功能默认短连接,通信完成自动关闭,如果你因项目需求要保持连接,可以重写receive_data方法,或者在请求时传header参数:(["Connection":"keep-alive"]),不过没有实现长连接数据发送功能,你可以自己调用socket_write方法发送数据,当前连接可以从全局变量Host_fd取得。
关于HTTP协议的更多资料可看:关于HTTP协议和WEBSOCKET协议的介绍
功能扩展
目前实现的请求比较基础,如果有需求可以自己扩展功能,只用根据自己的需要传参数给request()方法或重写相关方法即可,比如增加options请求:
inherit CORE_HTTP;
void options(string url)
{
Http::request("OPTIONS", url);
}