文章目录
搭建HTTP服务端
搭建HTTP服务端,主要用到三个类分别是:HTTPServer、HTTPRequestHandlerFactory、HTTPRequestHandler。HTTPServer负责监听特定的端口接收数据,接收的数据传递给HTTPRequestHandlerFactory,HTTPRequestHandlerFactory通过解析请求的参数在独立的线程中生成HTTPRequestHandler负责对每个独立的请求进行处理。服务端的搭建方法如下所示:
1.在主应用中启动HTTP服务
//MyHttpServer.h
#include "Poco/Util/ServerApplication.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/HTTPServer.h"
#include "Poco/Logger.h"
using namespace Poco;
using Poco::Util::ServerApplication;
using Poco::Net::HTTPServer;
using Poco::Net::ServerSocket;
class HttpApplication: public ServerApplication {
public:
HttpApplication(){ }
~HttpApplication() { }
protected:
//初始化操作
void initialize(Application& self);
//清理操作
void uninitialize();
//主函数入口
int main(const vector<string>& args);
private:
//http监听服务
HTTPServer * _httpSvr;
};
//MyHttpServer.cpp
#include "MyHttpServer.h"
void HttpApplication::initialize(Application& self) {
loadConfiguration();
ServerApplication::initialize(self);
}
void HttpApplication::uninitialize() {
ServerApplication::uninitialize();
}
int HttpApplication::main(const vector<string>& args)
{
//可以指定固定的端口也可以从外部配置
int port = 9876;
ServerSocket svs(port);
_httpSvr = new HTTPServer(new MyHTTPHandlerFactory(), svs, new HTTPServerParams);
_httpSvr->start();
//阻塞住进程
waitForTerminationRequest();
return Application::EXIT_OK;
}
2.在工厂类中处理请求
在工厂类中根据请求参数,区分不同的请求,然后生成对应的处理类。
//MyHttpHandlerFactory.h
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPRequestHandler.h"
using Poco::Net::HTTPRequestHandlerFactory;
using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPRequestHandler;
class MyHTTPHandlerFactory : public HTTPRequestHandlerFactory {
public:
HTTPRouteHandlerFactory(){};
~HTTPRouteHandlerFactory(){};
HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request);
};
//MyHttpHandlerFactory.cpp
#include "MyHttpHandlerFactory.h"
#include "Poco/URI.h"
using Poco::URI;
HTTPRequestHandler * MyHTTPHandlerFactory::createRequestHandler(const HTTPServerRequest & request)
{
if (request.getURI() == "/echoBody")
return new EchoBodyRequestHandler;
else if (request.getURI() == "/echoHeader")
return new EchoHeaderRequestHandler;
else if (request.getURI() == "/redirect")
return new RedirectRequestHandler;
else if (request.getURI() == "/auth")
return new AuthRequestHandler;
else if (request.getURI() == "/buffer")
return new BufferRequestHandler;
else if (request.getURI() == "/trailer")
return new TrailerRequestHandler;
else
return 0;
}
3.定义业务处理类
针对特定的业务请求,定义继承自HTTPRequestHandler的业务处理类。在特定的业务类中处理请求并响应。例子来源于官方示例。
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTTPServerRequest.h"
using Poco::Net::HTTPRequestHandler;
using Poco::Net::HTTPServerResponse;
using Poco::Net::HTTPServerRequest;
using Poco::Logger;
class EchoBodyRequestHandler: public HTTPRequestHandler
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
if (request.getChunkedTransferEncoding())
response.setChunkedTransferEncoding(true);
else if (request.getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
response.setContentLength(request.getContentLength());
response.setContentType(request.getContentType());
std::istream& istr = request.stream();
std::ostream& ostr = response.send();
StreamCopier::copyStream(istr, ostr);
}
};
class EchoHeaderRequestHandler: public HTTPRequestHandler
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
std::ostringstream osstr;
request.write(osstr);
int n = (int) osstr.str().length();
response.setContentLength(n);
std::ostream& ostr = response.send();
if (request.getMethod() != HTTPRequest::HTTP_HEAD)
request.write(ostr);
}
};
class RedirectRequestHandler: public AbstractHTTPRequestHandler
{
public:
void run()
{
response().redirect("http://www.appinf.com/");
}
};
class AuthRequestHandler: public HTTPRequestHandler
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
response.requireAuthentication("/auth");
response.send();
}
};
class BufferRequestHandler: public HTTPRequestHandler
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
std::string data("xxxxxxxxxx");
response.sendBuffer(data.data(), data.length());
}
};
class TrailerRequestHandler: public HTTPRequestHandler
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
std::string data("xxxxxxxxxx");
response.setChunkedTransferEncoding(true);
Poco::Net::MessageHeader& trailer = static_cast<Poco::Net::HTTPServerRequestImpl&>(request).session().responseTrailer();
trailer.set("Trailer-1", "Value 1");
trailer.set("Trailer-2", "Value 2");
response.send() << data;
}
};
4.解析请求参数
http业务请求中通常会包含一些请求参数,这里介绍一下请求参数的解析方法。
class AuthRequestHandler: public HTTPRequestHandler
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
try
{
//解析请求表单中的参数
HTMLForm format(request);
if (format.has("paramer1"))
{
std::string paramer1 = format.get("paramer1");
}
//解析http Content中的json数据
std::istream& istr = request.stream();
//判断内容是不是json,不是的话返回错误
if (request.getContentType() != std::string("application/json"))
{
//handle not json error
return;
}
//读取json数据
int content_length = (int)request.getContentLength();
char* request_content = new char[content_length + 1];
memset(request_content, 0x00, content_length + 1);
istr.read(request_content, content_length);
std::string my_request_str(request_content, content_length);
//释放分配的内存
if (request_content)
{
delete[] request_content;
}
//解析JSON内容
JSON::Parser parser;
Dynamic::Var result;
result = parser.parse(my_request_str);
JSON::Object::Ptr object_ptr = result.extract<JSON::Object::Ptr>();
if (object_ptr->has("paramer1"))
{
std::string paramer1 = object_ptr->get("paramer1").toString();
}
}
catch (Poco::Exception& e)
{
//handle exception
}
}
};
5.返回响应结果
将执行结果数据以json的形式反馈给客户端。
void AuthRequestHandler::sendResponseResult(HTTPServerRequest & request, HTTPServerResponse & response,
std::string result_info)
{
bool _bEnc = request.getChunkedTransferEncoding();
response.setChunkedTransferEncoding(_bEnc);
//设置内容格式为json
response.setContentType("application/json");
//允许跨域访问
response.add("Access-Control-Allow-Origin", "*");
response.add("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE");
response.add("Access-Control-Max-Age", "3600");
response.add("Access-Control-Allow-Headers", "x-requested-with,content-type");
response.add("Access-Control-Allow-Credentials", "true");
//响应反馈数据
std::ostream& response_stream = response.send();
response_stream << result_info;
response_stream.flush();
}
HTTP客户端请求
1.发送GET请求
bool SendGetRequest()
{
//请求的参数
std::string arg1 = "1";
std::string arg2 = "2";
std::string arg3 = "3";
//请求路径
std::string path = "/api/v1/get_request";
//设定服务器的地址
Poco::URI uri;
uri.setScheme("http");
uri.setHost("127.0.0.1");
uri.setPort(8800);
uri.setPath(path);
//添加请求参数
uri.addQueryParameter("arg1", arg1);
uri.addQueryParameter("arg2", arg2);
uri.addQueryParameter("arg3", arg3);
//定义客户端
Poco::Net::HTTPClientSession* http_session =
new HTTPClientSession();
http_session->setPort(uri.getPort());
http_session->setHost(uri.getHost());
//定义GET请求
std::string pathAndQuery(uri.getPathAndQuery());
Poco::Net::HTTPRequest request(
Poco::Net::HTTPRequest::HTTP_GET, pathAndQuery,
Poco::Net::HTTPMessage::HTTP_1_1);
//发送请求等待响应
Poco::Net::HTTPResponse response;
http_session->sendRequest(request);
std::istream &streamIn = http_session->receiveResponse(response);
//获取响应内容
std::ostringstream responseStream;
Poco::StreamCopier::copyStream(streamIn, responseStream);
std::string = responseContent = responseStream.str();
//释放资源
delete https_session;
https_session = nullptr;
return response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK;
}
2.发送POST请求
int sendPostRequest()
{
try
{
//指定服务器地址和访问路径
std::string path = "/api/v1/post_request";
Poco::URI uri;
uri.setScheme("http");
uri.setHost("127.0.0.1");
uri.setPort(8800);
uri.setPath(path);
//定义客户端
Poco::Net::HTTPClientSession* http_session =
new HTTPClientSession();
http_session->setHost(uri.getHost());
http_session->setPort(uri.getPort());
//定义POST请求
Poco::Net::HTTPRequest request(
Poco::Net::HTTPRequest::HTTP_POST, uri.getPathAndQuery(),
Poco::Net::HTTPMessage::HTTP_1_1);
//添加请求参数
Poco::Net::HTMLForm form;
form.add("arg1", "1");
form.add("arg2", "2");
form.add("arg3", "3");
form.prepareSubmit(request);
//发送请求等待响应
form.write(http_session->sendRequest(request));
Poco::Net::HTTPResponse response;
std::istream &streamIn = http_session->receiveResponse(response);
if (response.getStatus() != Poco::Net::HTTPResponse::HTTP_OK)
{
delete http_session;
http_session = nullptr;
return 1;
}
//获取响应结果
std::ostringstream responseStream;
Poco::StreamCopier::copyStream(streamIn, responseStream);
std::string resultStr = responseStream.str();
delete http_session;
http_session = nullptr;
//解析反馈的json结果
Poco::JSON::Parser parser;
auto root = parser.parse(resultStr);
Poco::JSON::Object::Ptr objRoot = root.extract<Poco::JSON::Object::Ptr>();
int codeResult = objRoot->getValue<int>("code");
if (codeResult == 200)
{
}
return codeResult;
}
catch (Poco::Exception& e)
{
//处理异常
}
}
3.发送MultiPart Post请求
int sendMutiPartRequest()
{
try
{
//请求路径和服务器配置
std::string path = "/api/v1/multipart";
Poco::URI uri;
uri.setScheme("http");
uri.setHost("127.0.0.1");
uri.setPort(8800);
uri.setPath(path);
//定义客户端
Poco::Net::HTTPClientSession* http_session =
new HTTPClientSession();
http_session->setHost(uri.getHost());
http_session->setPort(uri.getPort());
//生成对应的请求
Poco::Net::HTTPRequest request(
Poco::Net::HTTPRequest::HTTP_POST, uri.getPathAndQuery(),
Poco::Net::HTTPMessage::HTTP_1_1);
request.setContentType("multipart/form-data");
//在表单中添加对应的参数和文件
Poco::Net::HTMLForm form;
form.setEncoding(Poco::Net::HTMLForm::ENCODING_MULTIPART);
form.add("arg1", "1");
form.add("arg2", "2");
form.add("arg3", "3");
form.addPart("file", new Poco::Net::FilePartSource(filePath));
form.prepareSubmit(request);
//发送请求等待响应
form.write(http_session->sendRequest(request));
Poco::Net::HTTPResponse response;
std::istream &streamIn = http_session->receiveResponse(response);
if (response.getStatus() != Poco::Net::HTTPResponse::HTTP_OK)
{
delete https_session;
https_session = nullptr;
return 1;
}
//等待响应结果
std::ostringstream responseStream;
Poco::StreamCopier::copyStream(streamIn, responseStream);
std::string resultStr = responseStream.str();
delete https_session;
https_session = nullptr;
//解析JSON响应结果
Poco::JSON::Parser parser;
auto root = parser.parse(resultStr);
Poco::JSON::Object::Ptr objRoot = root.extract<Poco::JSON::Object::Ptr>();
int codeResult = objRoot->getValue<int>("code");
if(codeResult == 200)
{
return 0;
}
return codeResult;
}
catch (Poco::Exception& e)
{
//处理异常
}
}
4.下载文件
int downloadFileFromUrl(std::string url_path)
{
Poco::URI uri(url_path);
//定义客户端
Poco::Net::HTTPClientSession* http_session =
new HTTPClientSession();
http_session->setPort(uri.getPort());
http_session->setHost(uri.getHost());
//发送请求获取响应
Poco::Net::HTTPRequest request(
Poco::Net::HTTPRequest::HTTP_GET, uri.getPathAndQuery(),
Poco::Net::HTTPMessage::HTTP_1_1);
Poco::Net::HTTPResponse response;
https_session->sendRequest(request);
std::istream &streamIn = https_session->receiveResponse(response);
if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK)
{
//先下载到对应的临时文件
//先下载到临时文件再校验完整性之后再去替换对应的文件
}
}
使用HTTPS客户端
Poco::Net::HTTPSClientSession* GetHttpsClientSession()
{
//获取本地证书
std::string certificate_path = getCertificatePath();
//初始化证书信息
SSLManager::InvalidCertificateHandlerPtr handlerPtr(new AcceptCertificateHandler(false));
Context::Ptr context = new Context(Context::TLSV1_2_CLIENT_USE, certificate_path, Poco::Net::Context::VERIFY_NONE, 9);
SSLManager::instance().initializeClient(nullptr, handlerPtr, context);
//生成https客户端
HTTPSClientSession *session = new HTTPSClientSession(context);
//设置超时时间
session->setTimeout(5000 * 1000);
return session;
}