Tars 使用nghttp2 库 支持了 http2 协议,对协议库做了 RPC 封装,使得对业务开发几乎透明,用起来非常方便。由于复用了 Tars rpc,因此也拥有了同步和异步以及超时的特性,并能够利用 tars stat 上报调用质量。
本文简单介绍一下使用 http2 的方法和步骤,包括同步调用和异步调用, 实例代码参见 tarscpp/example/HttpDemo。
注意 tarscpp>=2.3 版本后接口变更成最新的了, 不在兼容老版本!并保持和 http1 接口一致性
http2 开启
只需要按照下面几个步骤设置:
编译 tars 框架,支持 nghttp2
tars 框架默认不开启 http2,开启 HTTP2:
Copy cmake .. -DTARS_HTTP2=ON
重新编译 tarscpp.
http2 server 实现
see demo: cpp/example/HttpDemo/Http2Server
自定义协议, 采用 http2
Copy void HttpServer :: initialize ()
{
addServant < Http2Imp >(ServerConfig :: Application + "." + ServerConfig :: ServerName + ".Http2Obj" );
addServantProtocol (ServerConfig :: Application + "." + ServerConfig :: ServerName + ".Http2Obj" , & parseHttp2);
}
协议解析器函数, 注意, 每个连接创建和保存一个 TC_Http2Server, 作为 http2 的 session 控制器
Copy 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 对象) 并解析协议, 回包即可
Copy 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:
Copy cmake .. -DTARS_HTTP2=ON
获取客户端代理,设置 http2 编解码函数
Copy CommunicatorPtr & comm = Application :: getCommunicator ();
ServantPrx prx = comm -> stringToProxy < ServantPrx > ( "test.server.yourobj" );
// set protocol
prox -> tars_set_protocol (ServantProxy :: PROTOCOL_HTTP2);
发起同步调用
Copy 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"
发起异步调用
Copy // 编写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"