使用 WinINET 为虚拟用户创建健壮的 HTTP 连接

Posted

技术标签:

【中文标题】使用 WinINET 为虚拟用户创建健壮的 HTTP 连接【英文标题】:Creating robust HTTP connection for dummy users with WinINET 【发布时间】:2010-12-24 08:31:08 【问题描述】:

我正在制作一个程序,它可以在 Windows 上从互联网上下载一个简单的文件,使用 Wininet 系列 API,因为我想利用其与 IE 兼容的代理行为。众所周知,当前的 IE 有几个代理设置:自动检测(WPAD)、自动配置(PAC)、手动单个 URL、每个协议的代理服务器、socks、直接……对于大多数用户来说,“直接下载“ 工作正常;但是对于某些用户(尤其是防火墙/NAT 后面的用户),他们在建立连接时总是需要特殊的代理设置。

编写代码来处理所有这些情况很痛苦,所以我希望带有InternetOpen (INTERNET_OPEN_TYPE_PRECONFIG) 的 WinINET 可以帮助我。它适用于大多数用户,但是我仍然发现一些用户抱怨连接失败。这些用户可能有非常特殊的网络环境(例如,代理需要用户名/密码验证),直接连接对他们不起作用。

有时虚拟用户配置错误,我希望 wininet 为我尝试“所有”可能的代理设置;不幸的是,INTERNET_OPEN_TYPE_PRECONFIG 只会尝试用户配置的那个,而不是“所有可能的代理设置”。

所以我的问题是,我如何为虚拟用户(即他们不了解如何配置他们的系统)制作一个具有最强解决所有 http 连接(尤其是代理配置)的能力的程序? 是否有任何建议的方法来建立 HTTP 连接而无需处理代理的东西? (即,一个“超级”连接求解器,它将尝试所有可能的代理设置),或者是否有任何方法告诉 WinINET 启用其所有代理设置来创建连接?

【问题讨论】:

弗朗西斯,我遇到过这个问题。简单的解决方案不存在;有太多变数,而贾斯汀描述的场景是唯一可靠的方法。更糟糕的是,这仅适用于 Internet Explorer——随着 Firefox 的市场份额不断增长,应该添加获取 Firefox 代理设置的方法以获得完整列表。 @J.J. - 好点子。我最初写答案时想到了firefox案例,并准备回来添加有关Firefox的步骤。你的cmets提醒我这样做!请参阅下面的新步骤 #4。 :-) 太糟糕了,没有简单的解决方案……有趣的是,也没有包含所有这些痛苦东西的库。我尝试过 libcurl 和 libproxy,但它们实际上是按照自己的方式工作,并不像 IE 那样工作。 【参考方案1】:

一个合理的算法应该是这样的:

    尝试使用用户当前的代理设置(IE 使用的代理设置)进行连接。这些是最有可能工作的。请参阅 MSDN 上的 WinHttpGetIEProxyConfigForCurrentUser() 以获取这些设置,或参阅 WinINet 中的 INTERNET_OPEN_TYPE_PRECONFIG

    如果失败,请尝试直接连接。

    如果失败,请尝试使用WinHttpGetProxyForUrl 进行 WPAD 自动检测。 (WPAD 是客户端可以在网络上找到Proxy Auto-Config (PAC) 文件的自动方式,通常是公司网络。)您需要选择检查代理文件的 DHCP 和 DNS 的选项。 MSDN 上的WinHTTP AutoProxy Functions 包含使用此 API 的代码示例和大量支持信息。如果此操作成功,您将取回代理信息,然后您可以将其插入您的 HTTP 下载代码。 AFAIK,没有等效的 WinINet 选项可以自动进行新的 WPAD 检测——只有 WinHTTP。

    接下来您可以尝试查找 Firefox 代理设置。 This SO answer 有关这些设置的位置和格式的详细信息,以便您可以通过编程方式访问它们。

    如果仍然失败,请让用户(在您的 UI 中)检查他们的互联网连接是否实际连接。实际上,与上述所有代理检测步骤失败相比,用户断开连接更为常见。要求用户打开他们的浏览器以确保他们可以访问互联网站点——如果上述步骤失败,他们的浏览器很可能无法看到网络。一旦用户声称他们已连接,请重复步骤 1-3。

    如果以上都失败了,你真的别无选择,只能要求用户手动指定他们的代理信息。您可能希望克隆 IE 或 firefox 的代理 UI,并将这些 UI 设置转换为适当的参数,以便在下载该文件时配置代理选项。

请注意,代理检测没有什么魔力——您可以选择使用用户设置、使用默认计算机设置、使用直接连接、使用 WPAD 查找 PAC 文件或询问用户。不幸的是,没有办法“在不需要处理代理的情况下建立 HTTP 连接”。

顺便说一句,虽然您可以仅将 WinHTTP 用于代理检测,然后使用 WinINet 获取文件,但我建议对这两个部分都使用 WinHTTP。当您想要最大的灵活性和对 HTTP 交互的控制(以及比 WinINet 更好的稳定性)时,WinHTTP 是更可取的。

更新 2:

J.J.上面有一个好主意——我添加了一个检查 Firefox 代理设置的步骤。由于奇怪的代理通常存在于公司环境中(倾向于在 IE 上标准化),因此这不太可能有所帮助,但值得一试。

更新:我刚刚编辑了上面的部分以回应 Francis 的正确评论:WinHTTP 不是严格意义上的 WinINet 的“继承者”(意味着 WinINet 的 100% 的功能都适用于WinHTTP)。相反,WinHTTP 是为使用 HTTP 进行数据交换并且不关心与 Internet Explorer 的缓存、cookie、拨号 UI 等集成的应用程序设计的。

服务器应用程序肯定属于这一类(WinHTTP 与 WinINet 不同,在服务器应用程序中使用是安全的)但许多客户端软件也使用它,例如每台现代 PC 上的 Windows Update 客户端。一般来说,WinHTTP 更适合需要通过 HTTP 下载文件、需要对网络进行更细粒度控制并希望控制自己的 UI 的客户端应用程序。

WinHTTP 更加亲力亲为(例如,您需要调用一个 API 来获取代理信息,然后调用另一个 API 来使用该代理信息),但是这种额外程度的控制允许您执行 WinINet 无法执行的操作,例如强制忽略用户的代理设置并尝试新的 WPAD 检测。

【讨论】:

我认为上面的过程就像是按顺序做所有的事情......对于只需要 HTTP 连接的程序来说,处理 WPAD 和 PAC 也太复杂了。同样根据 MSDN,WinHTTP 不是 WinINET 的继任者。它用于不同的(主要用于服务器端编程)目的。 嗨弗朗西斯-我更新了上面的答案以回复您的 cmets。你是对的,解决这个问题的方法是按顺序执行一组步骤——AFAIK 在 WinINet 或任何其他 Windows API 中没有“修复用户损坏的代理信息”功能。我还添加了更多信息以阐明您希望使用 WinINet 与 WinHTTP 的场景。 嗨 downvoter - 想评论您对此答案的担忧吗?我很乐意进行相应的修改。【参考方案2】:

我发现的关于 IE 本身使用的进程的最佳描述是 How the Windows Update client determines which proxy server to use to connect to the Windows Update Web site。将使用 IE 访问 Windows Update 时的顺序与您对 WinINet 或 WinHTTP WinHttpGetIEProxyConfigForCurrentUser、WinHttpDetectAutoProxyConfigUrl、WinHttpGetProxyForUrl 和 WinHttpGetDefaultProxyConfiguration 的了解相结合,以使您的应用程序连接。

这是知识库文章中的序列:

    如果用户配置为自动检测设置,请使用 WPAD 查找 PAC 文件。 没有找到 PAC 文件?如果用户设置了 IE 自动配置脚本,请使用该 PAC 文件。 仍然没有找到 PAC 文件?寻找代理。如果用户手动配置了 IE 代理设置,请使用它们。 没有配置 IE 代理?检查默认代理配置。 没有配置默认代理?使用直接连接。

【讨论】:

以上是关于使用 WinINET 为虚拟用户创建健壮的 HTTP 连接的主要内容,如果未能解决你的问题,请参考以下文章

集成 Windows 身份验证 Wininet

使用 wininet 设置代理设置

WinInet::InternetSetOption(...) 总是返回 0 并且 GetLastError() 返回 12018

如何在 C++ 中使用 wininet 创建 POST 请求

如何在 WinInet C++ 中获取 FTP 下载的进度

wininet如何处理cookies