【问题标题】:HttpSendRequest fails with error 12015HttpSendRequest 失败并出现错误 12015
【发布时间】:2011-03-11 14:17:48
【问题描述】:

我创建了一个 Win32 服务,它使用 WinInet 将 HTTP 请求发送到远程主机。在我的计算机 (WinXP SP2) 上,在我们的 QoS 团队 (Win2003 服务器) 的测试工作站上,它可以正常工作 - 通过代理和直接,代理有身份验证和没有身份验证。

但是我们的一些客户,在 Win2003 Server 上使用此服务 and_proxy_with_authorization,有一个问题 - HttpSendRequest 的所有调用都失败并且 GetLastError 返回 12015 (ERROR_INTERNET_LOGIN_FAILURE, The request to connect and login to an FTP 服务器失败)。至此,从 IE 地址行手动发送的相等 HTTP 请求成功。

代理配置似乎是正确的。这是初始化代码:

m_hNet = InternetOpen(m_strAgent.c_str(),
            INTERNET_OPEN_TYPE_PRECONFIG,
            NULL,
            NULL,
            0);

        // Respect explicit proxy
        if (Cfg::m_bUseProxy)
        {
            char szProxy[MAX_PATH] = {0};
            strncpy(szProxy, m_strProxyServer.c_str(), MAX_PATH - 1);

            INTERNET_PROXY_INFO proxyinfo;
            proxyinfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
            proxyinfo.lpszProxy = szProxy;
            proxyinfo.lpszProxyBypass = NULL;

            BOOL B = InternetSetOption(m_hNet, INTERNET_OPTION_PROXY, (LPVOID)(&proxyinfo), sizeof(proxyinfo));
            if (!B)
            {
                devent(TS::LL_HIGH, "[Wrn] InternetSetOption::Proxy failed <proxy=%s><le=%d>",
                    m_strProxyServer.c_str(),
                    GetLastError());
            }
        }


        // Validate handle
        if (NULL == m_hNet)
        {
            devent(TS::LL_CRITICAL, "[Err] InternetOpen failed <le=%d>",
                GetLastError());
            return false;
        }


        // Try to get connection handle
        m_hConnect = InternetConnect(m_hNet,
            m_strHostName.c_str(),
            INTERNET_DEFAULT_HTTP_PORT,
            NULL,
            NULL,
            INTERNET_SERVICE_HTTP,
            0,
            0);


        // Validate handle
        if (NULL == m_hConnect)
        {
            devent(TS::LL_CRITICAL, "[Err] InternetConnect failed <le=%d>",
                GetLastError());
            Cleanup();
            return false;
        }

        // Respect proxy authentication
        if (Cfg::m_bUseAuth)
        {
            BOOL B;
            B = InternetSetOption(m_hConnect, INTERNET_OPTION_PROXY_USERNAME, (LPVOID*)Cfg::m_strProxyLogin.c_str(), Cfg::m_strProxyLogin.length() + 1);
            if (!B)
            {
                devent(TS::LL_HIGH, "[Wrn] InternetSetOption::ProxyUserName failed <login=%s><le=%d>",
                    Cfg::m_strProxyLogin.c_str(),
                    GetLastError());
            }

            B = InternetSetOption(m_hConnect, INTERNET_OPTION_PROXY_PASSWORD, (LPVOID*)Cfg::m_strProxyPassword.c_str(), Cfg::m_strProxyPassword.length() + 1);
            if (!B)
            {
                devent(TS::LL_HIGH, "[Wrn] InternetSetOption::ProxyPassword failed <pass=%s><le=%d>",
                    Cfg::m_strProxyPassword.c_str(),
                    GetLastError());
            }
        }

这是发送:

// Try to get request handle
        m_hRequest = HttpOpenRequest(m_hConnect,
            "POST",
            m_strReqObject.c_str(),
            NULL,
            NULL,
            NULL,
            INTERNET_FLAG_NO_CACHE_WRITE,
            0);

        // Validate handle
        if (NULL == m_hRequest)
        {
            devent(TS::LL_CRITICAL, "[Err] OpenRequest failed <le=%d>",
                GetLastError());
            return false;
        }

        // Try to get response
        BOOL bOk = HttpSendRequest(m_hRequest,
            strSpecificHeaders.c_str(),
            strSpecificHeaders.length(),
            (LPVOID)strRequest.c_str(),
            (DWORD)strRequest.length());

        if (0 == bOk)
        {
            devent(TS::LL_CRITICAL, "[Err] SendRequest failed <le=%d>",
                GetLastError());

            CloseHandle(m_hRequest);
            return false;
        }

我用谷歌搜索了两天,但不仅没有找到解决方案,还没有找到任何人的类似问题。我也无法在类似的工作站上重现问题。最后,我不明白为什么 msdn 错误描述中的“FTP-Server”?

有什么想法吗?

【问题讨论】:

    标签: c++ proxy authorization wininet


    【解决方案1】:

    WinInet 专为应用程序空间用户使用而设计,并且与 WinInet 选项的注册表位置相关联(基于登录用户帐户)。

    在线 MSDN 文档在每个 WinInet 页面上都明确说明:

    注意 WinINet 不支持服务器实现。此外,不应从服务中使用它。对于服务器实现或服务,请使用Microsoft Windows HTTP Services (WinHTTP)

    WinInet 和 WinHTTP 在 API 上的区别非常小,你会很快学会的。

    • 函数重命名(例如 HttpOpenRequest -> WinHttpOpenRequest)
    • 所有 WinHttp 方法都只是 Unicode
    • 使用 WinHttp.lib、WinHttp.dll 代替 WinInet.lib、WinInet.dll

    还有一些其他的微妙之处,但你不会挣扎。

    我知道您的问题表明该代码适用于已经将其作为服务运行的人。但文档明确指出“不要这样做”这一事实可能表明某些版本的 Windows 可能不支持它,特别是更高版本,并且某些 Service Pack 或自动更新可能会导致当前工作实例失败。

    我会猜测,WinInet 甚至可能需要一些安全令牌和特权才能完成任务,并且某些 Windows Server 200x 安装可能具有默认设置,不向作为服务帐号。

    我真的建议尝试将快速测试服务移植到 WinHTTP 并在客户端的 Windows Server 实现上进行测试,看看是否能解决问题。

    【讨论】:

      【解决方案2】:

      采取完全不同的策略... ERROR_INTERNET_LOGIN_FAILURE 也可以表明防火墙已阻止该连接。

      Egg Head Cafe 此处描述了一种可能的解决方案

      【讨论】:

      • 链接坏了:(
      猜你喜欢
      • 1970-01-01
      • 2018-02-24
      • 2012-09-24
      • 2013-07-18
      • 2021-10-12
      • 2020-10-23
      • 2020-07-20
      • 2011-05-25
      • 2016-02-20
      相关资源
      最近更新 更多