环境: window10_x64 & vs2022
python版本: 3.9.13
日常开发中,会遇到c/c++作为客户端访问http/https服务的情况,今天整理下windows10环境下c/c++使用winhttp访问http/https服务的笔记,并提供相关资源下载。
我将从以下几个方面展开:
- http服务构建
- https证书生成及服务构建
- winhttp使用示例
- 资源下载
一、模拟http服务端
1、构建http服务
这里使用tornado来构建http服务。
示例代码(httpServer1.py):
#! /usr/bin/env python3
#-*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import tornado.httpserver
import json,time,datetime
settings = {
"debug" : False ,
}
def trace(reqType,reqBody):
msg = str(datetime.datetime.now()) + " , [" + reqType + "] , " + str(reqBody)
print(msg)
class MainHandler(tornado.web.RequestHandler):
def get(self):
trace("get",self.request.arguments)
#query = self.get_query_argument("query")
#print("query : %s" % query)
self.set_header('content-type', 'application/json')
#self.write(json.dumps({"result" : "test message"}))
self.finish(json.dumps({"result" : "get message"}))
def put(self):
trace("put",self.request.body)
self.finish(json.dumps({"result" : "put message"}))
def post(self):
#trace("post",self.request.arguments)
trace("post",self.request.body)
self.set_header('Content-type', 'application/json')
#self.set_header('Transfer-Encoding', 'chunked')
self.finish(json.dumps({"result" : "post message %d" % time.time()}))
if __name__ == "__main__":
port = 8093
print("listen on port %d"%port)
application = tornado.web.Application([
(r"/.*", MainHandler),
],**settings)
application.listen(port)
#http_server = tornado.httpserver.HTTPServer(application)
#http_server.bind(port,"0.0.0.0")
#http_server.start(num_processes=0)
tornado.ioloop.IOLoop.instance().start()
2、服务运行效果
curl测试命令如下:
curl -v http://127.0.0.1:8093 && echo ""
运行效果如下:
二、模拟https服务端
构建https服务,需要使用证书,这里使用自签名证书来实现。
1、生成证书
生成自签名证书(genCertTest1.bat):
goto start
cat > openssl.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = CN
ST = ShangHai
L = ShangHai
O = MyCompany
OU = Mike_Zhang@live.com
CN = localhost
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1
IP.1 = 127.0.0.1
EOF
:start
:: 生成包含SAN的证书
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes -config openssl.cnf -extensions v3_req
openssl.cnf文件内容如下:
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = CN
ST = ShangHai
L = ShangHai
O = MyCompany
OU = Mike_Zhang@live.com
CN = localhost
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1
IP.1 = 127.0.0.1
执行 genCertTest1.bat 脚本,会生产证书文件:

2、构建https服务
这里基于tornado来实现,添加ssl相关内容即可。
示例代码如下(httpsServer1.py):
#! /usr/bin/env python3
#-*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import tornado.httpserver
import json,time,datetime
import ssl
settings = {
"debug" : False ,
}
def trace(reqType,reqBody):
msg = str(datetime.datetime.now()) + " , [" + reqType + "] , " + str(reqBody)
print(msg)
class MainHandler(tornado.web.RequestHandler):
def get(self):
trace("get",self.request.arguments)
#query = self.get_query_argument("query")
#print("query : %s" % query)
self.set_header('content-type', 'application/json')
#self.write(json.dumps({"result" : "test message"}))
self.finish(json.dumps({"result" : "get message"}))
def put(self):
trace("put",self.request.body)
self.finish(json.dumps({"result" : "put message"}))
def post(self):
#trace("post",self.request.arguments)
trace("post",self.request.body)
self.set_header('Content-type', 'application/json')
self.finish(json.dumps({"result" : "post message %d" % time.time()}))
if __name__ == "__main__":
#ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_ctx.load_cert_chain(
certfile="server.crt",
keyfile="server.key"
)
ssl_ctx.options |= (
ssl.OP_NO_SSLv2 |
ssl.OP_NO_SSLv3 |
ssl.OP_NO_TLSv1 |
ssl.OP_NO_TLSv1_1 |
ssl.OP_NO_COMPRESSION
)
# 设置现代加密套件
ssl_ctx.set_ciphers(
'ECDHE-ECDSA-AES256-GCM-SHA384:'
'ECDHE-RSA-AES256-GCM-SHA384:'
'ECDHE-ECDSA-CHACHA20-POLY1305:'
'ECDHE-RSA-CHACHA20-POLY1305:'
'DHE-RSA-AES256-GCM-SHA384'
)
# 设置椭圆曲线
ssl_ctx.set_ecdh_curve('prime256v1') # 必需的安全设置
port = 8443
print("listen on port %d"%port)
app = tornado.web.Application([
(r"/.*", MainHandler),
],**settings)
http_server = tornado.httpserver.HTTPServer(app, ssl_options=ssl_ctx)
#http_server.listen(port)
http_server.bind(port,"0.0.0.0")
http_server.start()
tornado.ioloop.IOLoop.current().start()
3、服务运行效果
curl测试命令如下(忽略证书):
curl -vk https://127.0.0.1:8443 && echo ""
运行效果如下:
三、使用WinHTTP实现客户端
1、WinHTTP说明
Microsoft Windows HTTP 服务 (WinHTTP) 提供 HTTP 客户端应用程序编程接口 (API),以便通过 HTTP 协议将请求发送到其他 HTTP 服务器。
该服务提供 C/C++ 应用程序编程接口 (API) ,支持HTTPS协议。
文档地址:
https://learn.microsoft.com/zh-cn/windows/win32/winhttp/winhttp-start-page
c/c++接口文档地址:
https://learn.microsoft.com/zh-cn/windows/win32/winhttp/using-the-winhttp-c-c---api

2、使用示例
关键点:
1)使用 WinHttpConnect 函数创建连接;
2)使用WinHttpOpenRequest设置get/post方法、http/https协议等参数;
3)WinHttpAddRequestHeaders 设置http自定义请求头;
4)WinHttpSendRequest发送数据;
示例代码如下(winhttpTest1.cpp):

完整代码可从如下渠道获取:
关注微信公众号(聊聊博文,文末可扫码)后回复 20250709 获取。
运行效果如下:
四、资源获取
本文涉及资源可从如下渠道获取:
关注微信公众号(聊聊博文,文末可扫码)后回复 20250709 获取。
