如何让C++ HTTPS下载器具备代理感知能力以适配公司代理?
让C++ HTTPS下载器支持公司代理的解决方案
你的C++代码使用URLOpenBlockingStream无法通过公司代理,核心原因是这个API默认不会自动加载系统代理配置,也不处理代理认证;而C#的WebClient通过GetSystemWebProxy自动获取系统代理,并使用DefaultCredentials处理认证。以下是两种可行的解决方案:
方案一:为URLMON配置系统代理(基于原有代码修改)
URLOpenBlockingStream属于URLMON库,可通过URLMkSetSessionOption手动设置系统代理信息:
#include <urlmon.h> #include <wininet.h> #include <sstream> #include <iostream> #pragma comment(lib, "urlmon.lib") #pragma comment(lib, "wininet.lib") using namespace std; string downloader(char *url) { // 获取系统全局代理设置 INTERNET_PER_CONN_OPTION_LIST optionList = {0}; optionList.dwSize = sizeof(optionList); optionList.pszConnection = NULL; optionList.dwOptionCount = 1; optionList.pOptions = new INTERNET_PER_CONN_OPTION[1]; optionList.pOptions[0].dwOption = INTERNET_PER_CONN_PROXY_SERVER; DWORD dwSize = sizeof(optionList); if (!InternetQueryOption(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &optionList, &dwSize)) { delete[] optionList.pOptions; return ""; } // 将系统代理设置到URLMON会话 HRESULT hr = URLMkSetSessionOption(URLMON_OPTION_PROXY, optionList.pOptions[0].Value.pszValue, lstrlen(optionList.pOptions[0].Value.pszValue), 0); delete[] optionList.pOptions; if (FAILED(hr)) { return ""; } // 自动使用当前用户凭证处理代理认证(针对NTLM类型的公司代理) URLMkSetSessionOption(URLMON_OPTION_PROXY_USERNAME, "", 0, 0); URLMkSetSessionOption(URLMON_OPTION_PROXY_PASSWORD, "", 0, 0); // 原有下载逻辑 IStream *stream; HRESULT result = URLOpenBlockingStream(0, url, &stream, 0, 0); if (result != 0) { return ""; } char buffer[100]; unsigned long bytesRead; stringstream ss; stream->Read(buffer, 100, &bytesRead); while (bytesRead > 0U) { ss.write(buffer, (long long)bytesRead); stream->Read(buffer, 100, &bytesRead); } stream->Release(); string resultString = ss.str(); cout << resultString << endl; return resultString; }
方案二:改用WinINet API(推荐,更贴近C#逻辑)
WinINet是Windows原生网络库,支持自动读取系统代理、默认凭证认证,逻辑和C#的实现完全对齐:
#include <wininet.h> #include <sstream> #include <iostream> #pragma comment(lib, "wininet.lib") using namespace std; string downloader(char *url) { // 初始化网络会话,自动读取系统代理配置 HINTERNET hInternet = InternetOpenA("C++ Proxy-Aware Downloader", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hInternet) { return ""; } // 打开URL,自动处理代理连接 HINTERNET hConnect = InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE, 0); if (!hConnect) { InternetCloseHandle(hInternet); return ""; } // 读取响应内容 char buffer[100]; DWORD bytesRead; stringstream ss; while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) { ss.write(buffer, bytesRead); } // 释放资源 InternetCloseHandle(hConnect); InternetCloseHandle(hInternet); string resultString = ss.str(); cout << resultString << endl; return resultString; }
关键说明:
INTERNET_OPEN_TYPE_PRECONFIG参数让InternetOpen自动加载系统代理设置,对应C#的GetSystemWebProxy。- WinINet默认会使用当前登录用户的凭证处理代理认证,对应C#的
CredentialCache.DefaultCredentials,无需额外配置即可适配公司NTLM代理。 - WinINet比URLMON提供更灵活的代理控制,比如自定义代理地址、处理不同类型的认证等。
内容的提问来源于stack exchange,提问作者thirstforfirst
相关产品推荐
相关产品推荐

