HttpSendRequestA执行时程序无限挂起,如何设置超时规避该问题?
方案1:设置WinInet会话超时(改动最小的解决方案)
WinInet API默认没有配置超时阈值,遇到服务器无响应的场景就会无限阻塞,你可以在调用InternetOpenA之后,通过InternetSetOption函数全局配置各阶段的超时时间,配置会自动继承给后续创建的连接、请求对象。
参考代码添加到InternetOpenA调用之后即可:
// 所有超时时间单位为毫秒,以下示例统一设置为5秒超时 DWORD dwTimeout = 5000; // 域名解析超时 InternetSetOption(hInternet, INTERNET_OPTION_DOMAIN_RESOLVE_TIMEOUT, &dwTimeout, sizeof(dwTimeout)); // TCP连接超时 InternetSetOption(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, &dwTimeout, sizeof(dwTimeout)); // 请求发送超时 InternetSetOption(hInternet, INTERNET_OPTION_SEND_TIMEOUT, &dwTimeout, sizeof(dwTimeout)); // 响应接收超时 InternetSetOption(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, sizeof(dwTimeout));
配置完成后,HttpSendRequestA超时会返回FALSE,调用GetLastError可以获取到ERROR_INTERNET_TIMEOUT等明确的错误码,你可以判断错误类型后直接跳过当前请求,执行后续逻辑。
方案2:使用WinInet异步模式
如果你需要更灵活的请求控制,可以在调用InternetOpenA时添加INTERNET_FLAG_ASYNC标志开启异步模式,再通过InternetSetStatusCallback注册状态回调函数,所有网络操作都会变为非阻塞,请求的成功、失败、超时状态都会通过回调通知,完全不会阻塞主线程执行。
方案3:将请求逻辑放到独立工作线程执行
如果不想修改现有网络请求逻辑,可以把整套请求代码封装到独立函数中,通过std::thread或者系统API创建工作线程执行,主线程通过WaitForSingleObject等函数监听工作线程的执行状态,超过你预设的时间阈值后,可以选择终止线程或者直接忽略该请求的执行结果,继续执行主线程其他逻辑。
额外优化建议
当前你的代码请求的是GitHub API的80端口HTTP服务,目前GitHub API已经全面强制HTTPS,80端口请求会被重定向,建议将InternetConnectA的端口参数改为443,同时在HttpOpenRequestA的标志位中添加INTERNET_FLAG_SECURE启用HTTPS,避免请求失败。
内容的提问来源于stack exchange,提问作者Garlic2394

