HTTP2 支持
Tars 使用nghttp2 库支持了 http2 协议,对协议库做了 RPC 封装,使得对业务开发几乎透明,用起来非常方便。由于复用了 Tars rpc,因此也拥有了同步和异步以及超时的特性,并能够利用 tars stat 上报调用质量。
本文简单介绍一下使用 http2 的方法和步骤,包括同步调用和异步调用, 实例代码参见 tarscpp/example/HttpDemo。
注意 tarscpp>=2.3 版本后接口变更成最新的了, 不在兼容老版本!并保持和 http1 接口一致性
http2 开启
只需要按照下面几个步骤设置:
编译 tars 框架,支持 nghttp2
tars 框架默认不开启 http2,开启 HTTP2:
cmake .. -DTARS_HTTP2=ON
重新编译 tarscpp.
http2 server 实现
see demo: cpp/example/HttpDemo/Http2Server
自定义协议, 采用 http2
void HttpServer::initialize()
{
addServant<Http2Imp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".Http2Obj");
addServantProtocol(ServerConfig::Application + "." + ServerConfig::ServerName + ".Http2Obj", &parseHttp2);
}
协议解析器函数, 注意, 每个连接创建和保存一个 TC_Http2Server, 作为 http2 的 session 控制器
TC_NetWorkBuffer::PACKET_TYPE parseHttp2(TC_NetWorkBuffer&in, vector<char> &out)
{
TC_Http2Server*sessionPtr = (TC_Http2Server*)(in.getContextData());
if(sessionPtr == NULL)
{
shared_ptr<TC_Http2Server> session(new TC_Http2Server());
in.setContextData(session.get());
session->settings(3000);
TC_EpollServer::Connection *connection = (TC_EpollServer::Connection *)in.getConnection();
Http2Imp::addHttp2(connection->getId(), session);
sessionPtr = session.get();
}
return sessionPtr->parse(in, out);
}
服务实现中, 根据连接 id 获取到 http2 的 session(TC_Http2Server 对象) 并解析协议, 回包即可
int Http2Imp::doRequest(TarsCurrentPtr current, vector<char> &buffer)
{
shared_ptr<TC_Http2Server> session = getHttp2(current->getUId());
vector<shared_ptr<TC_Http2Server::Http2Context>> contexts = session->decodeRequest();
for(size_t i = 0; i< contexts.size(); ++i)
{
shared_ptr<TC_Http2Server::Http2Context> context = contexts[i];
vector<char> data;
context->response.setHeader("X-Header", "TARS");
context->response.setResponse(200, "OK", context->request.getContent());
int ret = session->encodeResponse(context, data);
if(ret != 0)
{
cout << "encodeResponse error:" << session->getErrMsg() << endl;
}
buffer.insert(buffer.end(), data.begin(), data.end());
}
return 0;
}
int Http2Imp::doClose(TarsCurrentPtr current)
{
delHttp2(current->getUId());
return 0;
}
http rpc 的使用
只需要按照下面几个步骤设置:
编译 tars 框架,支持 nghttp2
tars 框架默认不开启 http2,开启 HTTP2:
cmake .. -DTARS_HTTP2=ON
获取客户端代理,设置 http2 编解码函数
CommunicatorPtr& comm = Application::getCommunicator();
ServantPrx prx = comm->stringToProxy<ServantPrx>("test.server.yourobj");
// set protocol
prox->tars_set_protocol(ServantProxy::PROTOCOL_HTTP2);
发起同步调用
shared_ptr<TC_HttpResponse> rsp;
shared_ptr<TC_HttpRequest> req = std::make_shared<TC_HttpRequest>();
req->setPostRequest("http://domain.com/hello", string("helloworld-") + TC_Common::tostr(i), true);
prx->http_call("hello", req, rsp);
注意: 这里 http_call 第一个参数没有实际涵义, 只是用来监控用, 即在 web 管理平台接口统计看到函数名是”hello”
发起异步调用
// 编写callback
class MyHttpCb : public HttpCallback
{
public:
virtual int onHttpResponse(const shared_ptr<TC_HttpResponse> &rsp)
{
return 0;
}
virtual int onHttpResponseException(int expCode)
{
return 0;
}
};
// 发起调用
shared_ptr<TC_HttpRequest> req = std::make_shared<TC_HttpRequest>();
string buff = string("helloworld-") + TC_Common::tostr(i);
req->setPostRequest("http://domain.com/hello", buff, true);
prx->http_call_async("hello", req, p);
注意: 这里 http_call_async 第一个参数没有实际涵义, 只是用来监控用, 即在 web 管理平台接口统计看到函数名是”hello”