c++编写HTTP API服务端/客户端最简单的库,没有之一
libhv是c++编写HTTP API 服务端/客户端最简单的库,没有之一。具有以下特性:跨平台(Windows, Linux, Mac);支持RESTful;支持application/json、application/x-www-form-urlencoded、multipart/form-data;内置web service文件服务和indexof service目录服务;
libhv是c++编写HTTP API 服务端/客户端最简单的库,没有之一
具有以下特性:
- 跨平台(
Windows, Linux, Mac
) - 支持
https
- 支持
application/json
、application/x-www-form-urlencoded
、multipart/form-data
- 支持静态文件服务、目录服务、同步/异步
API
处理函数 - 支持
RESTful
风格、URI
路由、keep-alive
长连接、chunked
分块等特性 - http服务端类似
golang
的gin
- http客户端类似
python
的requests
- 可扩展
多进程/多线程
模型
libhv简介
libhv
是一个类似于libevent、libev、libuv
的跨平台网络库,提供了更简单的接口和更丰富的协议。
项目地址:https://github.com/ithewei/libhv.git
码云镜像:https://gitee.com/libhv/libhv.git
QQ技术交流群:739352073
libhv博客专栏:https://hewei.blog.csdn.net/category_9866493.html
libhv源码分析:https://blog.csdn.net/qu1993/category_10637982.html
http服务端最简版
见examples/http_server_test
添加好path=>handler
API路由,设置监听端口,调用http_server_run
即可
示例代码参考examples/http_server_test.cpp
#include "hv/HttpServer.h"
int main() {
HttpService router;
// curl -v http://ip:port/
router.Static("/", "./html");
// curl -v http://ip:port/proxy/get
router.Proxy("/proxy/", "http://httpbin.org/");
// curl -v http://ip:port/ping
router.GET("/ping", [](HttpRequest* req, HttpResponse* resp) {
return resp->String("pong");
});
// curl -v http://ip:port/data
router.GET("/data", [](HttpRequest* req, HttpResponse* resp) {
static char data[] = "0123456789";
return resp->Data(data, 10 /*, false */);
});
// curl -v http://ip:port/paths
router.GET("/paths", [&router](HttpRequest* req, HttpResponse* resp) {
return resp->Json(router.Paths());
});
// curl -v http://ip:port/get?env=1
router.GET("/get", [](HttpRequest* req, HttpResponse* resp) {
resp->json["origin"] = req->client_addr.ip;
resp->json["url"] = req->url;
resp->json["args"] = req->query_params;
resp->json["headers"] = req->headers;
return 200;
});
// curl -v http://ip:port/echo -d "hello,world!"
router.POST("/echo", [](const HttpContextPtr& ctx) {
return ctx->send(ctx->body(), ctx->type());
});
// curl -v http://ip:port/user/123
router.GET("/user/{id}", [](const HttpContextPtr& ctx) {
hv::Json resp;
resp["id"] = ctx->param("id");
return ctx->send(resp.dump(2));
});
http_server_t server;
server.port = 8080;
server.service = &router;
http_server_run(&server);
return 0;
}
友情提示:
上面示例直接运行在main主线程,http_server_run(&server, 1);
会阻塞当前线程运行,所以router
和server
对象不会被析构,如使用http_server_run(&server, 0);
内部会另起线程运行,不会阻塞当前线程,此时需要注意router
和server
的生命周期,不要定义为局部变量
被析构了,需定义为类成员变量或者全局变量
。
编译运行:
c++ -std=c++11 examples/http_server_test.cpp -o bin/http_server_test -lhv
bin/http_server_test
测试使用curl
或浏览器输入以下url
:
curl -v http://127.0.0.1:8080/ping
curl -v http://127.0.0.1:8080/data
curl -v http://127.0.0.1:8080/paths
curl -v http://127.0.0.1:8080/echo -d "hello,world"
curl -v http://127.0.0.1:8080/user/123
http客户端最简版
见examples/http_client_test
用法类似python
的requests
,requests::request
一个接口即可完成请求响应
#include "requests.h"
int main() {
auto resp = requests::get("http://www.example.com");
if (resp == NULL) {
printf("request failed!\n");
} else {
printf("%d %s\r\n", resp->status_code, resp->status_message());
printf("%s\n", resp->body.c_str());
}
auto resp2 = requests::post("127.0.0.1:8080/echo", "hello,world!");
if (resp2 == NULL) {
printf("request failed!\n");
} else {
printf("%d %s\r\n", resp2->status_code, resp2->status_message());
printf("%s\n", resp2->body.c_str());
}
return 0;
}
g++ -std=c++11 http_client_test.cpp -o http_client_test -Iinclude/hv -Llib -lhv
http服务端完整版
class Router {
public:
static void Register(HttpService& router) {
// preprocessor => Handler => postprocessor
router.preprocessor = Handler::preprocessor;
router.postprocessor = Handler::postprocessor;
router.largeFileHandler = Handler::largeFileHandler;
// router.errorHandler = Handler::errorHandler;
// curl -v http://ip:port/ping
router.GET("/ping", [](HttpRequest* req, HttpResponse* resp) {
return resp->String("pong");
});
// curl -v http://ip:port/data
router.GET("/data", [](HttpRequest* req, HttpResponse* resp) {
static char data[] = "0123456789";
return resp->Data(data, 10 /*, false */);
});
// curl -v http://ip:port/html/index.html
router.GET("/html/index.html", [](HttpRequest* req, HttpResponse* resp) {
return resp->File("html/index.html");
});
// curl -v http://ip:port/paths
router.GET("/paths", [&router](HttpRequest* req, HttpResponse* resp) {
return resp->Json(router.Paths());
});
// curl -v http://ip:port/get?env=1
router.GET("/get", [](HttpRequest* req, HttpResponse* resp) {
resp->json["origin"] = req->client_addr.ip;
resp->json["url"] = req->url;
resp->json["args"] = req->query_params;
resp->json["headers"] = req->headers;
return 200;
});
// curl -v http://ip:port/service
router.GET("/service", [](const HttpContextPtr& ctx) {
ctx->setContentType("application/json");
ctx->set("base_url", ctx->service->base_url);
ctx->set("document_root", ctx->service->document_root);
ctx->set("home_page", ctx->service->home_page);
ctx->set("error_page", ctx->service->error_page);
ctx->set("index_of", ctx->service->index_of);
return 200;
});
// curl -v http://ip:port/echo -d "hello,world!"
router.POST("/echo", [](const HttpContextPtr& ctx) {
return ctx->send(ctx->body(), ctx->type());
});
// wildcard *
// curl -v http://ip:port/wildcard/any
router.GET("/wildcard*", [](HttpRequest* req, HttpResponse* resp) {
std::string str = req->path + " match /wildcard*";
return resp->String(str);
});
// curl -v http://ip:port/async
router.GET("/async", [](const HttpRequestPtr& req, const HttpResponseWriterPtr& writer) {
writer->WriteHeader("X-Request-tid", hv_gettid());
std::async([req, writer](){
writer->WriteHeader("X-Response-tid", hv_gettid());
writer->WriteHeader("Content-Type", "text/plain");
writer->WriteBody("This is an async response.\n");
writer->End();
});
});
// curl -v http://ip:port/www.*
// curl -v http://ip:port/www.example.com
router.GET("/www.*", [](const HttpRequestPtr& req, const HttpResponseWriterPtr& writer) {
HttpRequestPtr req2(new HttpRequest);
req2->url = req->path.substr(1);
requests::async(req2, [writer](const HttpResponsePtr& resp2){
writer->Begin();
if (resp2 == NULL) {
writer->WriteStatus(HTTP_STATUS_NOT_FOUND);
writer->WriteHeader("Content-Type", "text/html");
writer->WriteBody("<center><h1>404 Not Found</h1></center>");
} else {
writer->WriteResponse(resp2.get());
}
writer->End();
});
});
// curl -v http://ip:port/sleep?t=1000
router.GET("/sleep", Handler::sleep);
// curl -v http://ip:port/setTimeout?t=1000
router.GET("/setTimeout", Handler::setTimeout);
// curl -v http://ip:port/query?page_no=1\&page_size=10
router.GET("/query", Handler::query);
// Content-Type: application/x-www-form-urlencoded
// curl -v http://ip:port/kv -H "content-type:application/x-www-form-urlencoded" -d 'user=admin&pswd=123456'
router.POST("/kv", Handler::kv);
// Content-Type: application/json
// curl -v http://ip:port/json -H "Content-Type:application/json" -d '{"user":"admin","pswd":"123456"}'
router.POST("/json", Handler::json);
// Content-Type: multipart/form-data
// bin/curl -v localhost:8080/form -F "user=admin pswd=123456"
router.POST("/form", Handler::form);
// curl -v http://ip:port/test -H "Content-Type:application/x-www-form-urlencoded" -d 'bool=1&int=123&float=3.14&string=hello'
// curl -v http://ip:port/test -H "Content-Type:application/json" -d '{"bool":true,"int":123,"float":3.14,"string":"hello"}'
// bin/curl -v http://ip:port/test -F 'bool=1 int=123 float=3.14 string=hello'
router.POST("/test", Handler::test);
// Content-Type: application/grpc
// bin/curl -v --http2 http://ip:port/grpc -H "content-type:application/grpc" -d 'protobuf'
router.POST("/grpc", Handler::grpc);
// RESTful API: /group/:group_name/user/:user_id
// curl -v -X DELETE http://ip:port/group/test/user/123
router.Delete("/group/:group_name/user/:user_id", Handler::restful);
// router.Delete("/group/{group_name}/user/{user_id}", Handler::restful);
// bin/curl -v localhost:8080/upload -F "file=@LICENSE"
router.POST("/upload", Handler::upload);
// curl -v http://ip:port/login -H "Content-Type:application/json" -d '{"username":"admin","password":"123456"}'
router.POST("/login", Handler::login);
}
};
完整版演示了application/json
、application/x-www-form-urlencoded
、multipart/form-data
、RESTful API
、多进程/多线程
赶快git clone
https://github.com/ithewei/libhv.git体验吧
git clone https://github.com/ithewei/libhv.git
cd libhv
make
bin/httpd -h
bin/httpd -d
#bin/httpd -c etc/httpd.conf -s restart -d
ps aux | grep httpd
# http file service
bin/curl -v localhost:8080
# http indexof service
bin/curl -v localhost:8080/downloads/
# http api service
bin/curl -v localhost:8080/ping
bin/curl -v localhost:8080/echo -d "hello,world!"
bin/curl -v localhost:8080/query?page_no=1\&page_size=10
bin/curl -v localhost:8080/kv -H "Content-Type:application/x-www-form-urlencoded" -d 'user=admin&pswd=123456'
bin/curl -v localhost:8080/json -H "Content-Type:application/json" -d '{"user":"admin","pswd":"123456"}'
bin/curl -v localhost:8080/form -F "user=admin pswd=123456"
bin/curl -v localhost:8080/upload -F "file=@LICENSE"
bin/curl -v localhost:8080/test -H "Content-Type:application/x-www-form-urlencoded" -d 'bool=1&int=123&float=3.14&string=hello'
bin/curl -v localhost:8080/test -H "Content-Type:application/json" -d '{"bool":true,"int":123,"float":3.14,"string":"hello"}'
bin/curl -v localhost:8080/test -F 'bool=1 int=123 float=3.14 string=hello'
# RESTful API: /group/:group_name/user/:user_id
bin/curl -v -X DELETE localhost:8080/group/test/user/123
更多推荐
所有评论(0)