C++使用WinHTTP访问http/https服务

环境: 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 获取。

相关推荐
十秒耿直拆包选手1 小时前
Qt:主窗体(QMainwindow)初始化注意事项
c++·qt
霖003 小时前
C++学习笔记三
运维·开发语言·c++·笔记·学习·fpga开发
mit6.8243 小时前
[shad-PS4] Vulkan渲染器 | 着色器_重新编译器 | SPIR-V 格式
c++·游戏引擎·ps4
tan77º4 小时前
【Linux网络编程】Socket - TCP
linux·网络·c++·tcp/ip
CHANG_THE_WORLD5 小时前
「macOS 系统字体收集器 (C++17 实现)」
开发语言·c++·macos
GiraKoo5 小时前
【GiraKoo】Breakpad 崩溃分析系统
c++
妄想出头的工业炼药师6 小时前
python和C++相互调用使用
开发语言·c++
景彡先生6 小时前
C++17 并行算法:std::execution::par
开发语言·c++
JiaJZhong6 小时前
力扣.最长回文子串(c++)
java·c++·leetcode