如果觉得小弟写的可以,请给一个点赞+关注支持
创建并启动http任务
示例
#include <workflow/WFFacilities.h>
int main(){
WFHttpTask * httpTask = WFTaskFactory::create_http_task("http://baidu.com",0,0,0);
protocol::HttpRequest *req = httpTask->get_req();
req->add_header_pair("Accept","*/*");
req->add_header_pair("User-Agent","myHttpTask");
req->set_header_pair("Connection","close");
httpTask->start();
pause();
}
创建任务方法原型
在workflow中所有的客户端任务都放在WFTaskFactory
工厂类中,
url:
请求的http urlredirect_max:
表示最大重定向次数。如果在请求过程中遇到重定向,该参数指定了最多允许重定向的次数。retry_max
:表示最大重试次数。如果请求失败,该参数指定了最多可以重试的次数。callback
:这是一个回调函数的指针,用于处理请求的响应。原型为using http_callback_t = std::function<void (WFHttpTask *)>;
说白了,就是一个参数为Task本身,没有返回值的函数。这个callback可以传NULL,表示无需callback。我们一切任务的callback都是这个风格。
#include "workflow/WFTaskFactory.h"
class WFTaskFactory
{
public:
static WFHttpTask *create_http_task(const std::string& url,
int redirect_max,
int retry_max,
http_callback_t callback);
}
代码解析
- 需要说明的是,所有工厂函数不会返回失败,所以不用担心task为空指针,哪怕是url不合法。一切错误都在callback再处理。
httpTask->get_req()
函数得到任务的request,默认是GET
方法,HTTP/1.1
,长连接
。框架会自动加上request_uri,Host等。- 框架会在发送前根据需要自动加上Content-Length或Connection这些http header。用户也可以通过
add_header_pair()
方法添加自己的header。 - 关于http消息的更多接口,可以在HttpMessage.h中查看。
httpTask->start()
启动任务,非阻塞,并且不会失败。之后callback必然会在被调用。因为异步的原因,start()以后显然不能再用httpTask指针了。- 为了让示例尽量简单,start()之后调用pause()防止程序退出,用户需要Ctrl-C结束程序。
处理http抓取结果
示例代码
首先,先看一眼示例代码
#include <workflow/WFFacilities.h>
#include <workflow/HttpMessage.h>
#include <workflow/HttpUtil.h>
void callback(WFHttpTask *httpTask){
//在回调函数中,可以获取任务的所有信息的
protocol::HttpRequest *req = httpTask->get_req();
protocol::HttpResponse *resp = httpTask->get_resp();
int state = httpTask->get_state();
int error = httpTask->get_error();
switch (state)
{
case WFT_STATE_SYS_ERROR:
fprintf(stderr,"system error: %s\n", strerror(error));
break;
case WFT_STATE_DNS_ERROR:
fprintf(stderr,"dns error: %s\n", gai_strerror(error));
break;
case WFT_STATE_SUCCESS:
break;
}
if(state != WFT_STATE_SUCCESS){
fprintf(stderr,"Failed\n");
return;
}
else{
fprintf(stderr,"Success!\n");
}
fprintf(stderr,"request\r\n %s %s %s\r\n", req->get_method(),
req->get_request_uri(),
req->get_http_version());
//使用迭代器来遍历首部字段
std::string name;
std::string value;
protocol::HttpHeaderCursor reqCursor(req);
while(reqCursor.next(name,value)){
fprintf(stderr,"%s:%s\r\n",name.c_str(),value.c_str());
}
fprintf(stderr,"\r\n");
fprintf(stderr,"response\r\n %s %s %s\r\n", resp->get_http_version(),
resp->get_status_code(),
resp->get_reason_phrase());
protocol::HttpHeaderCursor respCursor(resp);
while(respCursor.next(name,value)){
fprintf(stderr,"%s:%s\r\n",name.c_str(),value.c_str());
}
fprintf(stderr,"\r\n");
//print response body
const void *body;
size_t size;
resp->get_parsed_body(&body,&size);
//get_parsed_body方法会修改指针变量body的指向
fwrite(body,1,size,stderr);
}
//异步+回调
int main(){
signal(SIGINT,sigHandler);
WFHttpTask * httpTask = WFTaskFactory::create_http_task("http://baidu.com",0,0,callback);
protocol::HttpRequest *req = httpTask->get_req();
req->add_header_pair("Accept","*/*");
req->add_header_pair("User-Agent","myHttpTask");
req->set_header_pair("Connection","close");
httpTask->start();
pause();
}
代码解析
- 在这个callback里,httpTask就是我们通过工厂产生的httpTask。
httpTask->get_req()
得到任务的request,是HttpMessage
类的派生。req->get_method()
:获取请求方法,这里返回GET
req->get_request_uri()
:请求url,这里返回http://baidu.com
req->get_http_version()
:http版本,默认HTTP1.1
httpTask->get_resp()
得到任务的response,这个和request区别不大,都是HttpMessage的派生。resp->get_parsed_body(&body,&size)
获取http响应体,通过传入void*
的地址,也就是传入二级指针以及size
参数地址,,内部修改void*
指针的指向以及size
值,将其指向内部隐藏的响应体和大小,- 这个调用得到的是原始的http body,不解码chunk编码。如需解码chunk编码,可使用HttpUtil.h里的
httpTask->get_state()
与httpTask->get_error()
分别获得任务的运行状态和错误码。WFT_STATE_SUCCESS
表示运行正常,没有异常WFT_STATE_DNS_ERROR
表示出现dns
错误,一般是url
写错了WFT_STATE_SYS_ERROR
表示出现系统错误,
- 通过
HttpHeaderCursor
对象,对request
和response
的header
进行扫描。获取响应头,在HttpUtil.h可以看到Cursor的定义。
class HttpHeaderCursor
{
public:
HttpHeaderCursor(const HttpMessage *message);
...
void rewind();
...
bool next(std::string& name, std::string& value);
bool find(const std::string& name, std::string& value);
...
};
相信这个cursor在使用上应该不会有什么疑惑。
HttpChunkCursor
。 另外需要说明的是,find()
接口会修改cursor
内部的指针,即使用过find()过后如果仍然想对header进行遍历,需要通过rewind()
接口回到cursor
头部。