参考
httplib库原理
httplib搭建简单服务器与浏览器交互
httplib GitHub
该项目本部分需要实现本地客户端与远端服务器进行通信(例如国外网站),那么如果直接进行Socket连接将会非常慢或者撞墙,那么这个时候考虑使用本地客户端先与本地代理服务器进行通信,然后本地客户端每次访问一次URL地址,都需要将证书添加到受信任的根证书颁发机构,不然证书以及私钥对不上服务器将不允许访问。查看证书可以通过cmd命令行certmgr.msc访问证书管理器工具。
那么怎么将我们的CA证书添加到受信任的根证书颁发机构是本项目的第一个难点。我查阅了MSDN关于certmgr的相关命令
Certmgr.exe(证书管理器工具)
使用以下命令可以将想要添加的证书添加到root根目录。
certmgr /c /add TrustedCert.cer /s root
设置本地代理服务器就是需要将要访问的IP地址或者域名添加到本地环回地址127.0.0.1,这样每次访问远端服务器时,客户端先与本地代理服务器进行通信,并且通过CA证书与Server证书和Server私钥进行比对,比对成功则让客户端以为本地代理服务器即是需要访问的地址,现在需要的就是在浏览器中访问 https://www.xxx.com,让浏览器认为本地代理服务器就是 www.xxx.com,并且显示本地代理服务其返回的一句话(随便写,比如 hello xxx!)
添加IP地址或域名到环回地址的方式可以通过修改driver中的hosts文件得到,Win10用户的hosts文件路径如下:
C:\Windows\System32\drivers\etc\hosts
打开hosts文件(无后缀),显示如下:
# BitDefender has cleaned hosts file
127.0.0.1 localhost
#Original code from this file
#:# Copyright (c) 1993-2009 Microsoft Corp.
#:#
#:# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#:#
#:# This file contains the mappings of IP addresses to host names. Each
#:# entry should be kept on an individual line. The IP address should
#:# be placed in the first column followed by the corresponding host name.
#:# The IP address and the host name should be separated by at least one
#:# space.
#:#
#:# Additionally, comments (such as these) may be inserted on individual
#:# lines or following the machine name denoted by a '#' symbol.
#:#
#:# For example:
#:#
#:# 102.54.94.97 rhino.acme.com # source server
#:# 38.25.63.10 x.acme.com # x client host
#:# localhost name resolution is handled within DNS itself.
#:# 127.0.0.1 localhost
#:# ::1 localhost
#:127.0.0.1 ieonline.microsoft.com
127.0.0.1 ieonline.microsoft.com
在文件尾部添加一行代码,比如添加百度为环回地址:
这里需要注意!!!!如果后面需要正常访问百度则需要删除这一行,不然浏览器访问www.baidu.com会一直认为这是一个环回地址!
127.0.0.1 www.baidu.com
到这里代理服务器环境就搭建好了。
cpp-httplib是一个c++封装的http库,使用这个库可以在windows平台下完成http客户端、http服务端的搭建。
本次我们主要用到https客户端、https服务器端进行网络通信,值得一提的是httplib提供http、http2、https协议。
在用到https协议的时候,需要使用openSSL签发证书和私钥,另外https客服端的类名是SSLClient,它继承自Client类,https服务器端类名是SSLServer,它继承自Server类。
OpenSSL下载地址
OpenSSL生成CA证书、服务器证书及私钥
生成如下的.pem .crt证书文件
cert.pem转cert.crt文件的OpenSSL环境命令为:
openssl x509 -outform der -in cert.pem -out cert.crt
最终需要的证书如下:
因为本项目是在windowsPC端进行,所以开发IDE为VS2017
首先httplib库在windows 的头文件include格式为
1、通过宏开关CPPHTTPLIB_OPENSSL_SUPPORT控制是否使用Https
如果项目只使用https的话可以直接在头文件中输入一行代码,表示我们要使用的是https格式。
#define CPPHTTPLIB_OPENSSL_SUPPORT
2、然后要使用openSSL证书签发工具的,加入openssl包含路径:C:\OpenSSL-Win64\include,加入openssl的导入库路径C:\OpenSSL-Win64\lib,并链接libcrypto.lib、libssl.lib、openssl.lib
到此VShttplib环境就搭建好了。
需要支持OpenSSL的话 ,服务器和客户端的初始化格式如下:此过程需要CA证书、服务器证书、服务器私钥
服务端首先Get(),先注册对应关系,先告诉自己的服务器,当我们遇到什么请求方法,请求什么资源,在回调什么函数。将浙西全部都记录在map中。当listen监听的时候,才建立起服务端。
若服务端收到了http请求,解析之后。若请求中的path,对应了Get接口传入的path(也就是能在map中找到对应关系),则服务端会创建一个线程回调这个传入的函数helloworld()对这次的请求进行业务处理
服务器端监听的是www.ludashi.com,端口为8080
#include
#include
#include
#include
#include
#define SERVER_CERT_FILE "C:\\cert.pem"
#define SERVER_PRIVATE_KEY_FILE "C:\\key.pem"
//#define CPPHTTPLIB_OPENSSL_SUPPORT
using namespace std;
using namespace httplib;
#pragma comment(lib, "openssl.lib")
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")
std::string dump_headers(const Headers &headers) {
std::string s;
char buf[BUFSIZ];
for (auto it = headers.begin(); it != headers.end(); ++it) {
const auto &x = *it;
snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str());
s += buf;
}
return s;
}
std::string log(const Request &req, const Response &res) {
std::string s;
char buf[BUFSIZ];
s += "================================\n";
snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
req.version.c_str(), req.path.c_str());
s += buf;
std::string query;
for (auto it = req.params.begin(); it != req.params.end(); ++it) {
const auto &x = *it;
snprintf(buf, sizeof(buf), "%c%s=%s",
(it == req.params.begin()) ? '?' : '&', x.first.c_str(),
x.second.c_str());
query += buf;
}
snprintf(buf, sizeof(buf), "%s\n", query.c_str());
s += buf;
s += dump_headers(req.headers);
s += "--------------------------------\n";
snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str());
s += buf;
s += dump_headers(res.headers);
s += "\n";
if (!res.body.empty()) { s += res.body; }
s += "\n";
return s;
}
int main(void) {
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
cout << "Waiting for the connection..."<Hello ludashi!