如何在boost::asio::resolver::query中传递代理服务器的用户名和密码
使用boost::asio连接带身份验证的HTTP代理服务器
你的需求是实现和curl google.com --proxy http://username:password@xx.xxx.xxx.xx:xxxx等效的C++逻辑,boost::asio完全可以实现,你之前的写法错误在于混淆了代理地址解析和代理认证逻辑的步骤,导致解析失败报「Host not found (authoritative)」。
错误原因分析
你尝试的五种写法都存在问题:
- #1:如果
xx.xxx.xxx.xx没有用字符串引号包裹,会被编译器识别为变量而非IP字符串,导致解析失败;即使加了引号,这一步只是解析代理地址,但后续未发送认证请求,代理会拒绝连接,但你的报错是地址解析失败,大概率是未加引号导致。 - #2-#5:错误地将代理认证信息、目标URL混入
resolver::query中,resolver::query仅负责解析代理服务器的IP/域名和端口,这些额外信息不属于地址解析范畴,必然导致解析失败。
正确实现步骤
要连接带身份验证的HTTP代理,需要分两步:
- 解析代理服务器地址并建立TCP连接;
- 向代理发送
CONNECT请求,并在请求头中携带认证信息,请求代理建立到目标服务器的转发连接。
完整代码示例
#include <boost/asio.hpp> #include <string> #include <iostream> #include <vector> // 基础Base64编码实现(用于生成代理认证头) std::string base64_encode(const std::string& input) { const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; std::string result; int i = 0, j = 0; unsigned char char_array_3[3], char_array_4[4]; for (unsigned char c : input) { char_array_3[i++] = c; if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (i = 0; i < 4; i++) result += base64_chars[char_array_4[i]]; i = 0; } } if (i) { for (j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (j = 0; j < i + 1; j++) result += base64_chars[char_array_4[j]]; while (i++ < 3) result += '='; } return result; } int main() { try { boost::asio::io_context io_context; // 配置代理和目标服务器信息 const std::string proxy_host = "xx.xxx.xxx.xx"; const std::string proxy_port = "3128"; const std::string proxy_username = "username"; const std::string proxy_password = "password"; const std::string target_host = "google.com"; const std::string target_port = "80"; // 若访问HTTPS则改为443 // 1. 解析代理服务器地址 boost::asio::ip::tcp::resolver resolver(io_context); boost::asio::ip::tcp::resolver::query proxy_query( proxy_host, proxy_port, boost::asio::ip::tcp::resolver::query::numeric_service ); auto endpoint_iterator = resolver.resolve(proxy_query); // 2. 建立到代理的TCP连接 boost::asio::ip::tcp::socket socket(io_context); boost::asio::connect(socket, endpoint_iterator); // 3. 构造带认证的CONNECT请求 std::string auth_creds = proxy_username + ":" + proxy_password; std::string auth_header = "Proxy-Authorization: Basic " + base64_encode(auth_creds) + "\r\n"; std::string connect_request = "CONNECT " + target_host + ":" + target_port + " HTTP/1.1\r\n" "Host: " + target_host + ":" + target_port + "\r\n" + auth_header + "Connection: close\r\n\r\n"; // 4. 发送CONNECT请求到代理 boost::asio::write(socket, boost::asio::buffer(connect_request)); // 5. 读取代理响应,确认连接成功 boost::asio::streambuf response_buf; boost::asio::read_until(socket, response_buf, "\r\n"); std::istream response_stream(&response_buf); std::string http_version; unsigned int status_code; std::string status_msg; response_stream >> http_version >> status_code; std::getline(response_stream, status_msg); if (http_version.substr(0, 5) != "HTTP/" || status_code != 200) { std::cerr << "代理连接失败: " << status_code << " " << status_msg << std::endl; return 1; } // 读取剩余的响应头 boost::asio::read_until(socket, response_buf, "\r\n\r\n"); // 6. 连接成功后,向目标服务器发送HTTP请求(示例为GET请求) std::string get_request = "GET / HTTP/1.1\r\n" "Host: " + target_host + "\r\n" "Connection: close\r\n\r\n"; boost::asio::write(socket, boost::asio::buffer(get_request)); // 读取目标服务器响应 char buffer[1024]; while (true) { boost::system::error_code ec; size_t len = socket.read_some(boost::asio::buffer(buffer), ec); if (ec == boost::asio::error::eof) break; if (ec) throw boost::system::system_error(ec); std::cout.write(buffer, len); } } catch (std::exception& e) { std::cerr << "异常: " << e.what() << std::endl; } return 0; }
关键说明
- 代理地址解析:
resolver::query仅需传入代理的IP/域名和端口,无需额外信息,这是你之前写法的核心错误。 - 代理认证:通过在
CONNECT请求中添加Proxy-Authorization头实现,需要将username:password进行Base64编码。 - HTTPS支持:若目标是HTTPS服务器,在
CONNECT成功后,需要使用boost::asio::ssl::stream包装socket,完成TLS握手后再发送HTTPS请求。
内容的提问来源于stack exchange,提问作者Akshay Singh
相关产品推荐
相关产品推荐

