diff --git a/docs/tutorial-05-http_proxy.md b/docs/tutorial-05-http_proxy.md index 20d3ef57e3..0c8d3320d5 100644 --- a/docs/tutorial-05-http_proxy.md +++ b/docs/tutorial-05-http_proxy.md @@ -39,7 +39,7 @@ int main(int argc, char *argv[]) ~~~cpp static constexpr struct WFServerParams HTTP_SERVER_PARAMS_DEFAULT = { - .max_connections = 1000, + .max_connections = 2000, .peer_response_timeout = 10 * 1000, .receive_timeout = -1, .keep_alive_timeout = 60 * 1000, @@ -47,8 +47,8 @@ static constexpr struct WFServerParams HTTP_SERVER_PARAMS_DEFAULT = .ssl_accept_timeout = 10 * 1000, }; ~~~ -max_connections:最大连接数1000,达到上限之后会关闭最久未使用的keep-alive连接。没找到keep-alive连接,则拒绝新连接。 -peer_response_timeout:每读取到一块数据或发送出一块数据超时时间为10秒。 +max_connections:最大连接数2000,达到上限之后会关闭最久未使用的keep-alive连接。没找到keep-alive连接,则拒绝新连接。 +peer_response_timeout:每读取到一块数据或发送出一块数据的超时时间为10秒。 receive_timeout:接收一条完整的请求超时时间为-1,无限。 keep_alive_timeout:连接保持1分钟。 request_size_limit:请求包最大大小,无限制。 @@ -59,10 +59,10 @@ ssl_accept_timeout:完成ssl握手超时,10秒。 这个代理服务器本质上是将用户请求原封不动转发到对应的web server,再将web server的回复原封不动转发给用户。 浏览器发给proxy的请求里,request uri包含了scheme和host,port,转发时需要去除。 -例如,访问http://www.sogou.com/, 浏览器发送给proxy请求首行是: -GET http://www.sogou.com/ HTTP/1.1 +例如,访问`http://www.sogou.com/`, 浏览器发送给proxy请求首行是: +`GET` `http://www.sogou.com/` `HTTP/1.1` 需要改写为: -GET / HTTP/1.1 +`GET` `/` `HTTP/1.1` ~~~cpp void process(WFHttpTask *proxy_task) { @@ -97,9 +97,9 @@ void process(WFHttpTask *proxy_task) *series << http_task; } ~~~ -以上是process的全部内容。先解释向web server发送的http请求的构造。 +以上是process的全部内容。先解析向web server发送的http请求的构造。 req->get_request_uri()调用得到浏览器请求的完整URL,通过这个URL构建发往server的http任务。 -这个http任务重试与重定向都是0,因为重定向是由浏览器处理,遇到302等会重新发请求。 +这个http任务重试与重定向次数都是0,因为重定向是由浏览器处理,遇到302等会重新发请求。 ~~~cpp req->set_request_uri(http_task->get_req()->get_request_uri()); req->get_parsed_body(&body, &len); @@ -107,7 +107,7 @@ req->get_request_uri()调用得到浏览器请求的完整URL,通过这个URL *http_task->get_req() = std::move(*req); ~~~ 上面4个语句,其实是在生成发往web server的http请求。req是我们收到的http请求,我们最终要通过std::move()把它直接移动到新请求上。 -第一行实际上就是将request_uri里的http://host:port部分去掉,只保留path之后的部分。 +第一行实际上就是将request_uri里的`http://host:port`部分去掉,只保留path之后的部分。 第二第三行把解析下来的http body指定为向外输出的http body。需要做这个操作的原因是,我们的HttpMessage实现里, 解析得到的body和发送请求的body是两个域,所以这里需要简单的设置一下,无需复制内存。 第四行,一次性把请求内容转移给向web server发送的请求。 @@ -115,16 +115,17 @@ req->get_request_uri()调用得到浏览器请求的完整URL,通过这个URL # 异步server的工作原理 -显然process函数并不是proxy逻辑的全部,我们还需要处理从web server返回的http response,并填写返回给浏览器的response。 +显然process函数并不是proxy逻辑的全部,我们还需要处理从web server返回的http response,填写返回给浏览器的response。 在echo server的示例里,我们并不需要进行网络通信,直接填写返回页面就好。但proxy我们需要等待web server的结果。 -我们当然可以占用着的process函数的线程,等待结果返回,但这种同步等待的方式明显不是我们想要的。 -那么,我们就需要在异步的得到请求结果之后,再去回复用户请求,在等待结果期间,不能占用任何的线程。 +我们当然可以占用这个process函数的线程,等待结果返回,但这种同步等待的方式明显不是我们想要的。 +那么,我们就需要在异步得到请求结果之后,再去回复用户请求,在等待结果期间,不能占用任何的线程。 所以,在process的头部,我们给当前series设置了一个context,context里包含了proxy_task本身,以便我们异步填写结果。 ~~~cpp struct tutorial_series_context { std::string url; WFHttpTask *proxy_task; + bool is_keep_alive; }; void process(WFHttpTask *proxy_task) @@ -181,14 +182,14 @@ void http_callback(WFHttpTask *task) 因为返回给用户的数据可能很大,在我们这个示例里,设置为200MB上限。所以,和之前的示例不同,我们需要查看reply成功/失败状态。 http server任务和我们自行创建的http client任务的类型是完全相同的,都是WFHttpTask。不同的是server任务是框架创建的,它的callback初始为空。 server任务的callback和client一样,是在http交互完成之后被调用。所以,对server任务来讲,就是reply完成之后被调用。 -后面三行代码我们应该很熟悉了,无拷贝的将web server响应包转移到proxy响应包。 +后面三行代码我们应该很熟悉了,无拷贝地将web server响应包转移到proxy响应包。 在这个http_callback函数结束之后,对浏览器的回复被发送出,一切都是在异步的过程中进行。 剩下的一个函数是reply_callback(),在这里只为了打印一些log。在这个callback执行结束后,proxy task会被自动delete。 最后,series的callback里销毁context。 # Server回复的时机 -这里需要说明一下,回复消息的时机是在series里所有其它任务被执行完,自动回复,所以并没有task->reply()接口。 +这里需要说明一下,回复消息的时机是在series里所有其它任务被执行完后,自动回复,所以并没有task->reply()接口。 但是,有task->noreply()调用,如果对server任务执行了这个调用,在原本回复的时刻,直接关闭连接。但callback依然会被调用(状态为NOREPLY)。 在server任务的callback里,同样可以通过series_of()操作获得任务的series。那么,我们依然可以往这个series里追加新任务,虽然回复已经完成。 如果用户需要继续往series里追加任务,请务必参考[关于程序退出](./about-exit.md)的说明,因为这样做可能引起server关闭之后还有任务未完成的问题。