支持Http multipart/form-data 文件上传

优化http客户端超时逻辑
去除rtmp/rtsp代理时间戳覆盖逻辑
This commit is contained in:
xiongziliang 2018-06-21 14:03:43 +08:00
parent 4c82903ee8
commit ca885013af
8 changed files with 367 additions and 175 deletions

View File

@ -24,6 +24,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "Player/Player.h"
#include "Common/config.h" #include "Common/config.h"
#include "PlayerProxy.h" #include "PlayerProxy.h"
#include "Util/mini.h" #include "Util/mini.h"
@ -58,7 +59,7 @@ void PlayerProxy::play(const char* strUrl) {
return; return;
} }
if(strongSelf->m_pChn){ if(strongSelf->m_pChn){
strongSelf->m_pChn->inputH264((char *)data.data.data(), data.data.size(), 0); strongSelf->m_pChn->inputH264((char *)data.data.data(), data.data.size(), data.timeStamp);
}else{ }else{
strongSelf->initMedia(); strongSelf->initMedia();
} }
@ -69,7 +70,7 @@ void PlayerProxy::play(const char* strUrl) {
return; return;
} }
if(strongSelf->m_pChn){ if(strongSelf->m_pChn){
strongSelf->m_pChn->inputAAC((char *)data.data, data.aac_frame_length, 0); strongSelf->m_pChn->inputAAC((char *)data.data, data.aac_frame_length, data.timeStamp);
}else{ }else{
strongSelf->initMedia(); strongSelf->initMedia();
} }

View File

@ -36,6 +36,7 @@ HttpClient::HttpClient(){
HttpClient::~HttpClient(){ HttpClient::~HttpClient(){
} }
void HttpClient::sendRequest(const string &strUrl,float fTimeOutSec){ void HttpClient::sendRequest(const string &strUrl,float fTimeOutSec){
_aliveTicker.resetTime();
auto protocol = FindField(strUrl.data(), NULL , "://"); auto protocol = FindField(strUrl.data(), NULL , "://");
uint16_t defaultPort; uint16_t defaultPort;
bool isHttps; bool isHttps;
@ -73,15 +74,15 @@ void HttpClient::sendRequest(const string &strUrl,float fTimeOutSec){
_header.emplace(string("Accept-Language"),"zh-CN,zh;q=0.8"); _header.emplace(string("Accept-Language"),"zh-CN,zh;q=0.8");
_header.emplace(string("User-Agent"),"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"); _header.emplace(string("User-Agent"),"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36");
if(!_body.empty()){ if(_body && _body->remainSize()){
_header.emplace(string("Content-Length"),to_string(_body.size())); _header.emplace(string("Content-Length"),to_string(_body->remainSize()));
_header.emplace(string("Content-Type"),"application/x-www-form-urlencoded; charset=UTF-8"); _header.emplace(string("Content-Type"),"application/x-www-form-urlencoded; charset=UTF-8");
} }
bool bChanged = (_lastHost != host + ":" + to_string(port)) || (_isHttps != isHttps); bool bChanged = (_lastHost != host + ":" + to_string(port)) || (_isHttps != isHttps);
_lastHost = host + ":" + to_string(port); _lastHost = host + ":" + to_string(port);
_isHttps = isHttps; _isHttps = isHttps;
_fTimeOutSec = fTimeOutSec;
if(!alive() || bChanged){ if(!alive() || bChanged){
//InfoL << "reconnet:" << _lastHost; //InfoL << "reconnet:" << _lastHost;
startConnect(host, port,fTimeOutSec); startConnect(host, port,fTimeOutSec);
@ -93,33 +94,39 @@ void HttpClient::sendRequest(const string &strUrl,float fTimeOutSec){
void HttpClient::onConnect(const SockException &ex) { void HttpClient::onConnect(const SockException &ex) {
_aliveTicker.resetTime();
if(ex){ if(ex){
onDisconnect(ex); onDisconnect(ex);
return; return;
} }
_recvedBodySize = -1; _recvedBodySize = -1;
_recvedResponse.clear(); _recvedResponse.clear();
send(_method + " "); _StrPrinter printer;
send(_path + " HTTP/1.1\r\n"); printer << _method + " " << _path + " HTTP/1.1\r\n";
for (auto &pr : _header) { for (auto &pr : _header) {
send(pr.first + ": "); printer << pr.first + ": ";
send(pr.second + "\r\n"); printer << pr.second + "\r\n";
}
send("\r\n");
if (!_body.empty()) {
send(_body);
} }
send(printer << "\r\n");
onSend();
} }
void HttpClient::onRecv(const Buffer::Ptr &pBuf) { void HttpClient::onRecv(const Buffer::Ptr &pBuf) {
onRecvBytes(pBuf->data(),pBuf->size()); onRecvBytes(pBuf->data(),pBuf->size());
} }
void HttpClient::onErr(const SockException &ex) { void HttpClient::onErr(const SockException &ex) {
if(ex.getErrCode() == Err_eof && _totalBodySize == INT64_MAX){
//如果Content-Length未指定 但服务器断开链接
//则认为本次http请求完成
_totalBodySize = 0;
onResponseCompleted();
}
onDisconnect(ex); onDisconnect(ex);
} }
void HttpClient::onRecvBytes(const char* data, int size) { void HttpClient::onRecvBytes(const char* data, int size) {
if(_recvedBodySize == -1){ _aliveTicker.resetTime();
if(_recvedBodySize == -1){
//还没有收到http body这只是http头 //还没有收到http body这只是http头
auto lastLen = _recvedResponse.size(); auto lastLen = _recvedResponse.size();
_recvedResponse.append(data,size); _recvedResponse.append(data,size);
@ -132,6 +139,9 @@ void HttpClient::onRecvBytes(const char* data, int size) {
onResponseHeader(_parser.Url(),_parser.getValues()); onResponseHeader(_parser.Url(),_parser.getValues());
_totalBodySize = atoll(((HttpHeader &)_parser.getValues())["Content-Length"].data()); _totalBodySize = atoll(((HttpHeader &)_parser.getValues())["Content-Length"].data());
if(_totalBodySize == 0){
_totalBodySize = INT64_MAX;
}
_recvedBodySize = _recvedResponse.size() - pos - 4; _recvedBodySize = _recvedResponse.size() - pos - 4;
if(_totalBodySize < _recvedBodySize){ if(_totalBodySize < _recvedBodySize){
//http body 比声明的大 这个不可能的 //http body 比声明的大 这个不可能的
@ -149,6 +159,7 @@ void HttpClient::onRecvBytes(const char* data, int size) {
} }
if(_recvedBodySize >= _totalBodySize){ if(_recvedBodySize >= _totalBodySize){
_totalBodySize = 0;
onResponseCompleted(); onResponseCompleted();
} }
_recvedResponse.clear(); _recvedResponse.clear();
@ -159,6 +170,9 @@ void HttpClient::onRecvBytes(const char* data, int size) {
_recvedBodySize += size; _recvedBodySize += size;
onResponseBody(data,size,_recvedBodySize,_totalBodySize); onResponseBody(data,size,_recvedBodySize,_totalBodySize);
if(_recvedBodySize >= _totalBodySize){ if(_recvedBodySize >= _totalBodySize){
//如果接收的数据大于Content-Length
//则认为本次http请求完成
_totalBodySize = 0;
onResponseCompleted(); onResponseCompleted();
} }
return; return;
@ -171,8 +185,39 @@ void HttpClient::onRecvBytes(const char* data, int size) {
ErrorL << _totalBodySize << ":" << _recvedBodySize << "\r\n" << (printer << endl); ErrorL << _totalBodySize << ":" << _recvedBodySize << "\r\n" << (printer << endl);
shutdown(); shutdown();
} }
void HttpClient::onSend() {
_aliveTicker.resetTime();
while (_body && _body->remainSize() && !isSocketBusy()){
auto buffer = _body->readData();
if (!buffer){
//数据发送结束或读取数据异常
break;
}
if(send(buffer) <= 0){
//发送数据失败不需要回滚数据因为发送前已经通过isSocketBusy()判断socket可写
//所以发送缓存区肯定未满,该buffer肯定已经写入socket
break;
}
}
}
void HttpClient::onManager() {
if(_aliveTicker.elapsedTime() > 3 * 1000 && _totalBodySize == INT64_MAX){
//如果Content-Length未指定 但接收数据超时
//则认为本次http请求完成
_totalBodySize = 0;
onResponseCompleted();
}
if(_fTimeOutSec > 0 && _aliveTicker.elapsedTime() > _fTimeOutSec * 1000){
//超时
onDisconnect(SockException(Err_timeout,"http request timeout"));
shutdown();
}
}
} /* namespace Http */ } /* namespace Http */
} /* namespace ZL */ } /* namespace ZL */

View File

@ -27,6 +27,7 @@
#ifndef Http_HttpClient_h #ifndef Http_HttpClient_h
#define Http_HttpClient_h #define Http_HttpClient_h
#include <stdio.h>
#include <string.h> #include <string.h>
#include <functional> #include <functional>
#include <memory> #include <memory>
@ -41,8 +42,7 @@ using namespace ZL::Network;
namespace ZL { namespace ZL {
namespace Http { namespace Http {
class HttpArgs : public StrCaseMap class HttpArgs : public StrCaseMap {
{
public: public:
HttpArgs(){} HttpArgs(){}
virtual ~HttpArgs(){} virtual ~HttpArgs(){}
@ -60,7 +60,144 @@ public:
return ret; return ret;
} }
}; };
class HttpBody{
public:
typedef std::shared_ptr<HttpBody> Ptr;
HttpBody(){}
virtual ~HttpBody(){}
//剩余数据大小
virtual uint64_t remainSize() = 0;
virtual Buffer::Ptr readData() = 0;
};
class HttpBodyString : public HttpBody{
public:
typedef std::shared_ptr<HttpBodyString> Ptr;
HttpBodyString(const string &str){
_str = str;
}
virtual ~HttpBodyString(){}
uint64_t remainSize() override {
return _str.size();
}
Buffer::Ptr readData() override {
auto ret = std::make_shared<BufferString>(_str);
_str.clear();
return ret;
}
private:
mutable string _str;
};
class HttpMultiFormBody : public HttpBody {
public:
typedef std::shared_ptr<HttpMultiFormBody> Ptr;
HttpMultiFormBody(const StrCaseMap &args,const string &filePath,const string &boundary,uint32_t sliceSize = 4 * 1024){
_fp = fopen(filePath.data(),"rb");
if(!_fp){
throw std::invalid_argument(StrPrinter << "打开文件失败:" << filePath << " " << get_uv_errmsg());
}
auto fileName = filePath;
auto pos = filePath.rfind('/');
if(pos != string::npos){
fileName = filePath.substr(pos + 1);
}
_bodyPrefix = multiFormBodyPrefix(args,boundary,fileName);
_bodySuffix = multiFormBodySuffix(boundary);
_totalSize = _bodyPrefix.size() + _bodySuffix.size() + fileSize(_fp);
_sliceSize = sliceSize;
}
virtual ~HttpMultiFormBody(){
fclose(_fp);
}
uint64_t remainSize() override {
return _totalSize - _offset;
}
Buffer::Ptr readData() override{
if(_bodyPrefix.size()){
auto ret = std::make_shared<BufferString>(_bodyPrefix);
_offset += _bodyPrefix.size();
_bodyPrefix.clear();
return ret;
}
if(0 == feof(_fp)){
auto ret = std::make_shared<BufferRaw>(_sliceSize);
//读文件
int size;
do{
size = fread(ret->data(),1,_sliceSize,_fp);
}while(-1 == size && UV_EINTR == get_uv_error(false));
if(size == -1){
_offset = _totalSize;
WarnL << "fread failed:" << get_uv_errmsg();
return nullptr;
}
_offset += size;
ret->setSize(size);
return ret;
}
if(_bodySuffix.size()){
auto ret = std::make_shared<BufferString>(_bodySuffix);
_offset = _totalSize;
_bodySuffix.clear();
return ret;
}
return nullptr;
}
public:
static string multiFormBodyPrefix(const StrCaseMap &args,const string &boundary,const string &fileName){
string MPboundary = string("--") + boundary;
_StrPrinter body;
for(auto &pr : args){
body << MPboundary << "\r\n";
body << "Content-Disposition: form-data; name=\"" << pr.first << "\"\r\n\r\n";
body << pr.second << "\r\n";
}
body << MPboundary << "\r\n";
body << "Content-Disposition: form-data; name=\"" << "file" << "\";filename=\"" << fileName << "\"\r\n";
body << "Content-Type: application/octet-stream\r\n\r\n" ;
return body;
}
static string multiFormBodySuffix(const string &boundary){
string MPboundary = string("--") + boundary;
string endMPboundary = MPboundary + "--";
_StrPrinter body;
body << "\r\n" << endMPboundary;
return body;
}
static uint64_t fileSize(FILE *fp) {
auto current = ftell(fp);
fseek(fp,0L,SEEK_END); /* 定位到文件末尾 */
auto end = ftell(fp); /* 得到文件大小 */
fseek(fp,current,SEEK_SET);
return end - current;
}
static string multiFormContentType(const string &boundary){
return StrPrinter << "multipart/form-data; boundary=" << boundary;
}
private:
FILE *_fp;
string _bodyPrefix;
string _bodySuffix;
uint64_t _offset = 0;
uint64_t _totalSize;
uint32_t _sliceSize;
};
class HttpClient : public TcpClient class HttpClient : public TcpClient
{ {
public: public:
@ -71,7 +208,7 @@ public:
virtual void sendRequest(const string &url,float fTimeOutSec); virtual void sendRequest(const string &url,float fTimeOutSec);
void clear(){ void clear(){
_header.clear(); _header.clear();
_body.clear(); _body.reset();
_method.clear(); _method.clear();
_path.clear(); _path.clear();
_recvedResponse.clear(); _recvedResponse.clear();
@ -83,10 +220,18 @@ public:
void setHeader(const HttpHeader &header){ void setHeader(const HttpHeader &header){
_header = header; _header = header;
} }
void addHeader(const string &key,const string &val){ HttpClient & addHeader(const string &key,const string &val,bool force = false){
_header.emplace(key,val); if(!force){
_header.emplace(key,val);
}else{
_header[key] = val;
}
return *this;
} }
void setBody(const string &body){ void setBody(const string &body){
_body.reset(new HttpBodyString(body));
}
void setBody(const HttpBody::Ptr &body){
_body = body; _body = body;
} }
const string &responseStatus(){ const string &responseStatus(){
@ -96,8 +241,6 @@ public:
return _parser.getValues(); return _parser.getValues();
} }
protected: protected:
bool _isHttps;
virtual void onResponseHeader(const string &status,const HttpHeader &headers){ virtual void onResponseHeader(const string &status,const HttpHeader &headers){
DebugL << status; DebugL << status;
}; };
@ -109,24 +252,28 @@ protected:
} }
virtual void onRecvBytes(const char *data,int size); virtual void onRecvBytes(const char *data,int size);
virtual void onDisconnect(const SockException &ex){} virtual void onDisconnect(const SockException &ex){}
private: protected:
virtual void onConnect(const SockException &ex) override; virtual void onConnect(const SockException &ex) override;
virtual void onRecv(const Buffer::Ptr &pBuf) override; virtual void onRecv(const Buffer::Ptr &pBuf) override;
virtual void onErr(const SockException &ex) override; virtual void onErr(const SockException &ex) override;
virtual void onSend() override;
virtual void onManager() override;
protected:
bool _isHttps;
private:
//send //send
HttpHeader _header; HttpHeader _header;
string _body; HttpBody::Ptr _body;
string _method; string _method;
string _path; string _path;
//recv //recv
string _recvedResponse; string _recvedResponse;
size_t _recvedBodySize; int64_t _recvedBodySize;
size_t _totalBodySize; int64_t _totalBodySize;
Parser _parser; Parser _parser;
string _lastHost; string _lastHost;
Ticker _aliveTicker;
float _fTimeOutSec = 0;
}; };

View File

@ -43,8 +43,6 @@ HttpDownloader::~HttpDownloader() {
void HttpDownloader::startDownload(const string& url, const string& filePath,bool bAppend,float timeOutSecond) { void HttpDownloader::startDownload(const string& url, const string& filePath,bool bAppend,float timeOutSecond) {
_filePath = filePath; _filePath = filePath;
_timeOutSecond = timeOutSecond;
_downloadTicker.resetTime();
if(_filePath.empty()){ if(_filePath.empty()){
_filePath = exeDir() + "HttpDownloader/" + MD5(url).hexdigest(); _filePath = exeDir() + "HttpDownloader/" + MD5(url).hexdigest();
} }
@ -68,7 +66,6 @@ void HttpDownloader::startDownload(const string& url, const string& filePath,boo
} }
void HttpDownloader::onResponseHeader(const string& status,const HttpHeader& headers) { void HttpDownloader::onResponseHeader(const string& status,const HttpHeader& headers) {
_downloadTicker.resetTime();
if(status != "200" && status != "206"){ if(status != "200" && status != "206"){
//失败 //失败
shutdown(); shutdown();
@ -83,22 +80,11 @@ void HttpDownloader::onResponseHeader(const string& status,const HttpHeader& hea
} }
void HttpDownloader::onResponseBody(const char* buf, size_t size, size_t recvedSize, size_t totalSize) { void HttpDownloader::onResponseBody(const char* buf, size_t size, size_t recvedSize, size_t totalSize) {
_downloadTicker.resetTime();
if(_saveFile){ if(_saveFile){
fwrite(buf,size,1,_saveFile); fwrite(buf,size,1,_saveFile);
} }
} }
//string getMd5Sum(const string &filePath){
// auto fp = File::createfile_file(filePath.data(),"rb");
// fseek(fp,0,SEEK_END);
// auto sz = ftell(fp);
// char tmp[sz];
// fseek(fp,0,SEEK_SET);
// auto rd = fread(tmp,1,sz,fp);
// InfoL << sz << " " << rd;
// fclose(fp);
// return MD5(string(tmp,sz)).hexdigest();
//}
void HttpDownloader::onResponseCompleted() { void HttpDownloader::onResponseCompleted() {
closeFile(); closeFile();
//InfoL << "md5Sum:" << getMd5Sum(_filePath); //InfoL << "md5Sum:" << getMd5Sum(_filePath);
@ -128,14 +114,6 @@ void HttpDownloader::closeFile() {
} }
} }
void HttpDownloader::onManager(){
if(_downloadTicker.elapsedTime() > _timeOutSecond * 1000){
//超时
onDisconnect(SockException(Err_timeout,"download timeout"));
shutdown();
}
}
} /* namespace Http */ } /* namespace Http */
} /* namespace ZL */ } /* namespace ZL */

View File

@ -52,16 +52,12 @@ private:
void onResponseBody(const char *buf,size_t size,size_t recvedSize,size_t totalSize) override; void onResponseBody(const char *buf,size_t size,size_t recvedSize,size_t totalSize) override;
void onResponseCompleted() override; void onResponseCompleted() override;
void onDisconnect(const SockException &ex) override; void onDisconnect(const SockException &ex) override;
void onManager() override;
void closeFile(); void closeFile();
private:
FILE *_saveFile = nullptr; FILE *_saveFile = nullptr;
string _filePath; string _filePath;
onDownloadResult _onResult; onDownloadResult _onResult;
uint32_t _timeOutSecond;
bool _bDownloadSuccess = false; bool _bDownloadSuccess = false;
Ticker _downloadTicker;
}; };
} /* namespace Http */ } /* namespace Http */

View File

@ -59,18 +59,9 @@ void HttpRequester::onDisconnect(const SockException &ex){
void HttpRequester::startRequester(const string &url,const HttpRequesterResult &onResult , float timeOutSecond){ void HttpRequester::startRequester(const string &url,const HttpRequesterResult &onResult , float timeOutSecond){
_onResult = onResult; _onResult = onResult;
_resTicker.resetTime();
_timeOutSecond = timeOutSecond;
sendRequest(url,timeOutSecond); sendRequest(url,timeOutSecond);
} }
void HttpRequester::onManager(){
if(_onResult && _resTicker.elapsedTime() > _timeOutSecond * 1000){
//超时
onDisconnect(SockException(Err_timeout,"wait http response timeout"));
shutdown();
}
}
}//namespace Http }//namespace Http

View File

@ -39,18 +39,15 @@ public:
typedef std::function<void(const SockException &ex,const string &status,const HttpHeader &header,const string &strRecvBody)> HttpRequesterResult; typedef std::function<void(const SockException &ex,const string &status,const HttpHeader &header,const string &strRecvBody)> HttpRequesterResult;
HttpRequester(); HttpRequester();
virtual ~HttpRequester(); virtual ~HttpRequester();
void startRequester(const string &url,const HttpRequesterResult &onResult,float timeOutSecond = 10); void startRequester(const string &url,const HttpRequesterResult &onResult,float timeOutSecond = 10);
private: private:
void onResponseHeader(const string &status,const HttpHeader &headers) override; void onResponseHeader(const string &status,const HttpHeader &headers) override;
void onResponseBody(const char *buf,size_t size,size_t recvedSize,size_t totalSize) override; void onResponseBody(const char *buf,size_t size,size_t recvedSize,size_t totalSize) override;
void onResponseCompleted() override; void onResponseCompleted() override;
void onDisconnect(const SockException &ex) override; void onDisconnect(const SockException &ex) override;
void onManager() override; private:
string _strRecvBody; string _strRecvBody;
HttpRequesterResult _onResult; HttpRequesterResult _onResult;
Ticker _resTicker;
float _timeOutSecond;
}; };
}//namespace Http }//namespace Http

View File

@ -42,116 +42,153 @@ using namespace ZL::Poller;
using namespace ZL::Network; using namespace ZL::Network;
int main(int argc,char *argv[]){ int main(int argc, char *argv[]) {
//设置退出信号处理函数 //设置退出信号处理函数
signal(SIGINT, [](int){EventPoller::Instance().shutdown();}); signal(SIGINT, [](int) { EventPoller::Instance().shutdown(); });
//设置日志 //设置日志
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace)); Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>()); Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
///////////////////////////////http downloader/////////////////////// {
//下载器map ///////////////////////////////http downloader///////////////////////
map<string,HttpDownloader::Ptr> downloaderMap; //下载器map
//下载两个文件一个是http下载一个https下载 map<string, HttpDownloader::Ptr> downloaderMap;
auto urlList = {"http://img3.imgtn.bdimg.com/it/u=158031390,1321729164&fm=214&gp=0.jpg", //下载两个文件一个是http下载一个https下载
"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=931786003,1029770543&fm=27&gp=0.jpg"}; auto urlList = {"http://img3.imgtn.bdimg.com/it/u=158031390,1321729164&fm=214&gp=0.jpg",
"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=931786003,1029770543&fm=27&gp=0.jpg"};
for(auto &url : urlList){ for (auto &url : urlList) {
//创建下载器 //创建下载器
HttpDownloader::Ptr downloader(new HttpDownloader()); HttpDownloader::Ptr downloader(new HttpDownloader());
downloader->setOnResult([](ErrCode code,const char *errMsg,const char *filePath){ downloader->setOnResult([](ErrCode code, const char *errMsg, const char *filePath) {
DebugL << "=====================HttpDownloader result======================="; DebugL << "=====================HttpDownloader result=======================";
//下载结果回调 //下载结果回调
if(code == Err_success){ if (code == Err_success) {
//文件下载成功 //文件下载成功
InfoL << "download file success:" << filePath; InfoL << "download file success:" << filePath;
}else{ } else {
//下载失败 //下载失败
WarnL << "code:" << code << " msg:" << errMsg; WarnL << "code:" << code << " msg:" << errMsg;
} }
}); });
//断点续传功能,开启后可能会遇到416的错误因为上次文件已经下载完全 //断点续传功能,开启后可能会遇到416的错误因为上次文件已经下载完全
downloader->startDownload(url,exeDir() + MD5(url).hexdigest() + ".jpg",true); downloader->startDownload(url, exeDir() + MD5(url).hexdigest() + ".jpg", true);
//下载器必须被强引用,否则作用域一失效就会导致对象销毁 //下载器必须被强引用,否则作用域一失效就会导致对象销毁
downloaderMap.emplace(url,downloader); downloaderMap.emplace(url, downloader);
} }
///////////////////////////////http get/////////////////////// ///////////////////////////////http get///////////////////////
//创建一个Http请求器 //创建一个Http请求器
HttpRequester::Ptr requesterGet(new HttpRequester()); HttpRequester::Ptr requesterGet(new HttpRequester());
//使用GET方式请求 //使用GET方式请求
requesterGet->setMethod("GET"); requesterGet->setMethod("GET");
//设置http请求头我们假设设置cookie当然你也可以设置其他http头 //设置http请求头我们假设设置cookie当然你也可以设置其他http头
requesterGet->addHeader("Cookie","SESSIONID=e1aa89b3-f79f-4ac6-8ae2-0cea9ae8e2d7"); requesterGet->addHeader("Cookie", "SESSIONID=e1aa89b3-f79f-4ac6-8ae2-0cea9ae8e2d7");
//开启请求该api会返回当前主机外网ip等信息 //开启请求该api会返回当前主机外网ip等信息
requesterGet->startRequester("http://pv.sohu.com/cityjson?ie=utf-8",//url地址 requesterGet->startRequester("http://pv.sohu.com/cityjson?ie=utf-8",//url地址
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功 [](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
const string &status, //http回复的状态码比如说200/404 const string &status, //http回复的状态码比如说200/404
const HttpClient::HttpHeader &header, //http回复头 const HttpClient::HttpHeader &header, //http回复头
const string &strRecvBody){ //http回复body const string &strRecvBody) { //http回复body
DebugL << "=====================HttpRequester GET==========================="; DebugL << "=====================HttpRequester GET===========================";
if(ex){ if (ex) {
//网络相关的错误 //网络相关的错误
WarnL << "network err:" << ex.getErrCode() << " " << ex.what(); WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
}else{ } else {
//打印http回复信息 //打印http回复信息
_StrPrinter printer; _StrPrinter printer;
for(auto &pr: header){ for (auto &pr: header) {
printer << pr.first << ":" << pr.second << "\r\n"; printer << pr.first << ":" << pr.second << "\r\n";
} }
InfoL << "status:" << status << "\r\n" InfoL << "status:" << status << "\r\n"
<< "header:\r\n" << (printer << endl) << "header:\r\n" << (printer << endl)
<< "\r\nbody:" << strRecvBody; << "\r\nbody:" << strRecvBody;
} }
}); });
///////////////////////////////http post/////////////////////// ///////////////////////////////http post///////////////////////
//创建一个Http请求器 //创建一个Http请求器
HttpRequester::Ptr requesterPost(new HttpRequester()); HttpRequester::Ptr requesterPost(new HttpRequester());
//使用POST方式请求 //使用POST方式请求
requesterPost->setMethod("POST"); requesterPost->setMethod("POST");
//设置http请求头 //设置http请求头
requesterPost->addHeader("X-Requested-With","XMLHttpRequest"); requesterPost->addHeader("X-Requested-With", "XMLHttpRequest");
requesterPost->addHeader("Origin","http://fanyi.baidu.com"); requesterPost->addHeader("Origin", "http://fanyi.baidu.com");
//设置POST参数列表 //设置POST参数列表
HttpArgs args; HttpArgs args;
args["query"] = "test"; args["query"] = "test";
args["from"] = "en"; args["from"] = "en";
args["to"] = "zh"; args["to"] = "zh";
args["transtype"] = "translang"; args["transtype"] = "translang";
args["simple_means_flag"] = "3"; args["simple_means_flag"] = "3";
requesterPost->setBody(args.make()); requesterPost->setBody(args.make());
//开启请求 //开启请求
requesterPost->startRequester("http://fanyi.baidu.com/langdetect",//url地址 requesterPost->startRequester("http://fanyi.baidu.com/langdetect",//url地址
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功 [](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
const string &status, //http回复的状态码比如说200/404 const string &status, //http回复的状态码比如说200/404
const HttpClient::HttpHeader &header, //http回复头 const HttpClient::HttpHeader &header, //http回复头
const string &strRecvBody){ //http回复body const string &strRecvBody) { //http回复body
DebugL << "=====================HttpRequester POST=========================="; DebugL << "=====================HttpRequester POST==========================";
if(ex){ if (ex) {
//网络相关的错误 //网络相关的错误
WarnL << "network err:" << ex.getErrCode() << " " << ex.what(); WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
} else { } else {
//打印http回复信息 //打印http回复信息
_StrPrinter printer; _StrPrinter printer;
for(auto &pr: header){ for (auto &pr: header) {
printer << pr.first << ":" << pr.second << "\r\n"; printer << pr.first << ":" << pr.second << "\r\n";
} }
InfoL << "status:" << status << "\r\n" InfoL << "status:" << status << "\r\n"
<< "header:\r\n" << (printer << endl) << "header:\r\n" << (printer << endl)
<< "\r\nbody:" << strRecvBody; << "\r\nbody:" << strRecvBody;
} }
}); });
//事件轮询 ///////////////////////////////http upload///////////////////////
EventPoller::Instance().runLoop(); //创建一个Http请求器
//清空下载器 HttpRequester::Ptr requesterUploader(new HttpRequester());
downloaderMap.clear(); //使用POST方式请求
requesterGet.reset(); requesterUploader->setMethod("POST");
requesterPost.reset(); //设置http请求头
//程序开始退出 HttpArgs argsUploader;
EventPoller::Destory(); argsUploader["query"] = "test";
AsyncTaskThread::Destory(); argsUploader["from"] = "en";
Logger::Destory(); argsUploader["to"] = "zh";
return 0; argsUploader["transtype"] = "translang";
argsUploader["simple_means_flag"] = "3";
static string boundary = "0xKhTmLbOuNdArY";
HttpMultiFormBody::Ptr body(new HttpMultiFormBody(argsUploader, exePath(), boundary));
requesterUploader->setBody(body);
requesterUploader->addHeader("Content-Type", HttpMultiFormBody::multiFormContentType(boundary));
//开启请求
requesterUploader->startRequester("http://fanyi.baidu.com/langdetect",//url地址
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
const string &status, //http回复的状态码比如说200/404
const HttpClient::HttpHeader &header, //http回复头
const string &strRecvBody) { //http回复body
DebugL << "=====================HttpRequester Uploader==========================";
if (ex) {
//网络相关的错误
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
} else {
//打印http回复信息
_StrPrinter printer;
for (auto &pr: header) {
printer << pr.first << ":" << pr.second << "\r\n";
}
InfoL << "status:" << status << "\r\n"
<< "header:\r\n" << (printer << endl)
<< "\r\nbody:" << strRecvBody;
}
});
//事件轮询
EventPoller::Instance().runLoop();
}
//程序开始退出
EventPoller::Destory();
AsyncTaskThread::Destory();
Logger::Destory();
return 0;
} }