写点什么

Qt|使用 Http 通讯下载文件

  • 2022 年 7 月 18 日
  • 本文字数:2788 字

    阅读完需:约 9 分钟

Qt|使用Http通讯下载文件

前提

在某些功能中,会使用到通过 Http 通讯从网址上下载资源信息。

在这里,我说的资源信息是指以.png、.mp4 以及.doc 为后缀的文件。只是做一个简单的功能实现。

需要实现的功能:根据网址 url 将文件下载到指定位置,并实时显示下载进度。

HTTP 通讯下载

下载文件,首先需要将文件下载下来。

为了方便使用,一般情况下,我们会将接口设置成简单明了的形式。

这里,我们设置了三个参数

int HttpDownLoad(int enumType, std::string strRemoteFile, std::string strLocalFile);
复制代码

参数讲解:

enumType:当前表示下载的方式,是 http?https

strRemoteFile:url 的完整路径

strLocalFile:下载到指定位置的全路径

我们在使用过程中,对外开放这一个接口,就完全可以实现下载功能啦!

请求 http 文件

对于 HTTP 的使用,无外乎就是这样一个流程:创建会话,建立连接,建立请求,数据操作

对于下载功能来说,在创建会话之前,需要分析传入的 url 网址。

分解 URL 网址

使用 WinHttpCrackUrl 方式,可以将一个给定的 url 分解,设置到 URL_COMPONENTS 这个结构体中。

这一步骤是必须要操作的!

URL_INFO url_info = { 0 };URL_COMPONENTSW lpUrlComponents = { 0 };lpUrlComponents.dwStructSize = sizeof(lpUrlComponents);lpUrlComponents.lpszExtraInfo = url_info.szExtraInfo;lpUrlComponents.lpszHostName = url_info.szHostName;lpUrlComponents.lpszPassword = url_info.szPassword;lpUrlComponents.lpszScheme = url_info.szScheme;lpUrlComponents.lpszUrlPath = url_info.szUrlPath;lpUrlComponents.lpszUserName = url_info.szUserName;
lpUrlComponents.dwExtraInfoLength = 512;lpUrlComponents.dwHostNameLength = 512;lpUrlComponents.dwPasswordLength = 512;lpUrlComponents.dwSchemeLength = 512;lpUrlComponents.dwUrlPathLength = 512;lpUrlComponents.dwUserNameLength = 512;
if (!WinHttpCrackUrl(strRemoteFile, 0, ICU_ESCAPE, &lpUrlComponents)){ return GetLastError();}
复制代码

说明:这里需要注意的是 512,如果你的 url 网址太长了,需要修改这个数值。否则会产生错误!

创建会话

对于一个应用程序,WinHttpOpen 函数初始化 WinHTTP 函数的使用,并返回一个 WinHTTP 会话句柄。


// 创建一个会话HINTERNET hSession = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, NULL);
复制代码


参数说明:

参数 1:一个指向字符串变量的指针,该变量包含调用 WinHTTP 函数的应用程序或实体的名称。一般我们会采用 null 使用。

参数 2:利用默认的代办服务器

参数 3:如果参数 2 未设置为 WINHTTP_ACCESS_TYPE_NAMED_PROXY,则此参数必须设置为 WINHTTP_NO_PROXY_NAME。

参数 4:如果参数 2 未设置为“WINHTTP_ACCESS_TYPE_NAMED_PROXY”,该参数必须设置“WINHTTP_NO_PROXY_BYPASS”

参数 5:一般采用 null

创建连接

WinHttpConnect 函数指定 HTTP 请求的初始目标服务器,并为该初始目标返回一个 HTTP 会话的 HINTERNET 连接句柄。

HINTERNET hConnect = WinHttpConnect(hSession, lpUrlComponents.lpszHostName, lpUrlComponents.nPort, 0);
复制代码

参数说明:

参数 1:WinHttpOpen 的返回参数

参数 2:该字符串包含 HTTP 服务器的主机名

参数 3:该字符串包含 HTTP 服务器的端口号

参数 4:该参数为保留参数,且必须为 0!!!

创建请求

在创建请求时,我们需要注意,这里要根据是 http 通讯还是 https 通讯设置不同的标识。

if (enumType == HttpType_HTTP){  dwFlags = WINHTTP_FLAG_REFRESH;}else if (enumType == HttpType_HTTPS){  dwFlags = WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE;}
复制代码

WinHttpOpenRequest 函数创建一个 HTTP 请求句柄。

HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", lpUrlComponents.lpszUrlPath, L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, dwFlags);if (enumType == HttpType_HTTPS){  DWORD  dwFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA |    SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |    SECURITY_FLAG_IGNORE_CERT_CN_INVALID |    SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;  //设置支持https  if (!WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags)))  {    return GetLastError();  }}
复制代码

发送请求

WinHttpSendRequest 函数向 HTTP 服务器发送指定的请求。

if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)){  return GetLastError();}
复制代码

参数说明:

参数 1:是 WinHttpOpenRequest 的句柄

参数 2:如果没有附加的头文件,这个参数可以是 WINHTTP_NO_ADDITIONAL_HEADERS。

参数 3:一个无符号长整数值,包含附加头的字符长度。如果该参数为-1L 且 pwszHeaders 不为 NULL,则该函数假设 pwszHeaders 为 NULL 结束,并计算其长度。一般我们只用 0 代替就可以了。

参数 4:如果没有可选的数据要发送,这个参数可以是 WINHTTP_NO_REQUEST_DATA。

参数 5:如果没有可选数据要发送,此参数可以为零。

参数 6:发送的总数据的长度

参数 7:指针指向一个指针大小的变量,该变量包含一个应用程序定义的值,该值与请求句柄一起传递给任何回调函数。这里默认是 0 即可。

接收 http 请求响应

WinHttpReceiveResponse 函数等待接收由 WinHttpSendRequest 发起的 HTTP 请求的响应

当 winhttpreceiverresponse 成功完成时,状态码和响应头已经被接收,应用程序可以使用 WinHttpQueryHeaders 来检查。

if (!WinHttpReceiveResponse(hRequest, 0)){  return GetLastError();}
复制代码

到这里我们就可以获取文件的长度了!

文件操作

获取文件长度

DWORD dwContentSize = 0, dwIndex = 0, dwSizeDW = sizeof(dwSizeDW);WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwContentSize, &dwSizeDW, &dwIndex);
复制代码

根据获取的文件长度,创建一个本地文件进行存储数据了。

实时下载文件

WinHttpQueryDataAvailable 函数返回可用 WinHttpReadData 读取的数据量(以字节为单位)。

使用 while 循环的方式,逐字节获取,并实时写入到文件中

DWORD  dwSize, dwWrite, dwCalcSize = 0;while (WinHttpQueryDataAvailable(hRequest, &dwSize) && dwSize){  ZeroMemory(pBuffer, 4096);  WinHttpReadData(hRequest, pBuffer, dwSize, &dwSize);  WriteFile(hFile, pBuffer, dwSize, &dwWrite, NULL);}
复制代码

最后,数据写完之后,关闭文件,并关闭 http 通讯!

总结

看到这里,使用 http 通讯方式下载文件就完成了。


难点 1:在下载 https 文件时,会有证书的问题,不过没关系,这种验证方式我已经说明了,只要按照我的方式肯定可以获取到,前提是你的证书必须要合法,否则我也无法帮助你啦!


难点 2:下载文件时,一定要先创建文件路径,再存储。最好采用 CreateFile 的方式。


我是中国好公民 st,一名 C++开发程序媛~

发布于: 刚刚阅读数: 5
用户头像

书山有路勤为径,学海无涯苦作舟 2022.07.01 加入

擅长语言:C++ 涉及语言:Python

评论

发布
暂无评论
Qt|使用Http通讯下载文件_HTTP_中国好公民st_InfoQ写作社区