让你在MUD中更轻松的使用HTTP协议和网站通信

本站教程关于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方式,因为更简单强大。


使用说明

对需要请求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);

注意目前此模块不支持https协议,只能使用http网址,url格式:

"http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]

请求数据(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取得。

功能扩展

目前实现的请求比较基础,如果有需求可以自己扩展功能,只用根据自己的需要传参数给request()方法或重写相关方法即可,比如增加options请求:

inherit CORE_HTTP;

void options(string url)
{
    Http::request("OPTIONS", url);
}
京ICP备13031296号-4