topsail 2023-06-02 22:16 采纳率: 50%
浏览 64
已结题

关于在httpclient中使用代理的问题

我的项目是.net 7.0,使用httpclient访问互联网上的rest api服务,但是这个服务需要通过代理服务器才能访问,于是我设置了代理,代码如下

var webProxy = new WebProxy("address", false);
var proxyHttpClientHandler = new HttpClientHandler
                {
                    Proxy = webProxy,
                    UseProxy = true
                };
                
ICredentials credential = new NetworkCredential("user001", "psw");
webProxy.Credentials = credential;
httpClient = new HttpClient(proxyHttpClientHandler);

通过get方法抓取测试网页可以正常返回html内容,说明代理工作正常。
通过post方法,调用rest api则经常失败(不是每次都失败,这点也不太理解),提示“连接被断开”错误。
检查代理服务器日志发现,每次post,实际产生两个请求,一个是所谓的preflight request,对于这个请求,代理服务器日志显示407错误,并且无访问者的username,说明没有携带Credential,对于第二个请求,日志则显示正常转发,并且有访问者的username,说明携带了Credential信息。

我的代理服务器是ubuntu+squid。两条日志信息如下
TCP_DENIED/407 3954 CONNECT api.xxx.com:443 - HIER_NONE/- text/html
TCP_TUNNEL/200 2653 CONNECT api.xxx.com:443 user001 HIER_DIRECT/100.18.6.192

补充一下,具体的错误如下:

InnerException    {"Unable to read data from the transport connection: 远程主机强迫关闭了一个现有的连接。."}    System.Exception {System.IO.IOException}
SocketErrorCode    ConnectionReset    System.Net.Sockets.SocketError

先谢谢各位的回答,我在stackoverflow上找到了部分答案,那就是preflight request请求返回407是http代理协议的正常步骤之一!所以高度怀疑是gfw导致的问题,于是我将程序部署到国外,一切正常了。那么问题变为:如何绕开gfw?因为Get请求一直正常,但Post就会被断开连接。所以代理服务器的ip是没有被彻底屏蔽的。

  • 写回答

4条回答 默认 最新

  • weixin_47044707 2023-06-02 22:35
    关注

    以下回答由chatGPT-4 plus与答主共同编写:
    看起来你的问题可能与CORS(跨源资源共享)有关。这是一种由网页浏览器实施的安全机制,用于限制从一个源的网页如何和另一个源的资源交互。

    在某些情况下,例如当你发出一个跨源的POST请求时,浏览器会首先发送一个"预检"请求(即所谓的"preflight"请求)。这是一个OPTIONS请求,用于检查实际请求是否安全发送。如果服务器回应这个预检请求表示它允许这个操作,那么浏览器才会发送实际的POST请求。否则,浏览器将阻止请求,并向用户显示一个错误。

    看起来在你的情况下,这个预检请求没有携带凭证,可能是因为你在你的HttpClientHandler对象上设置了UseDefaultCredentials属性为false。你可以试试以下的修改:

    var webProxy = new WebProxy("address", false);
    var proxyHttpClientHandler = new HttpClientHandler
    {
        Proxy = webProxy,
        UseProxy = true,
        UseDefaultCredentials = false, // 设置为false
        Credentials = new NetworkCredential("user001", "psw"), // 直接在这里设置凭证
    };
    httpClient = new HttpClient(proxyHttpClientHandler);
    

    这样设置后,你的HttpClient应该会在所有请求中都使用你提供的凭证,包括预检请求。

    如果这个改变还是没有解决问题,你可能需要在你的代理服务器上调整配置,使其在收到预检请求时不需要凭证,或者允许匿名预检请求。这可能需要修改Squid的配置文件。

    请注意,虽然这样的修改可能会解决你的问题,但它也可能会使你的代理服务器对匿名预检请求更加开放,这可能有潜在的安全风险。你应该根据你的具体需求和环境考虑这个问题。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 6月5日
  • 修改了问题 6月3日
  • 创建了问题 6月2日

悬赏问题

  • ¥66 换电脑后应用程序报错
  • ¥50 array数据同步问题
  • ¥15 pic16F877a单片机的外部触发中断程序仿真失效
  • ¥15 Matlab插值拟合差分微分规划图论
  • ¥15 keil5 target not created
  • ¥15 C/C++数据与算法请教
  • ¥15 怎么找志同道合的伙伴
  • ¥20 如何让程序ab.eXe自已删除干净硬盘里的本文件自己的ab.eXe文件
  • ¥50 爬虫预算充足,跪巨佬
  • ¥15 滑块验证码拖动问题悬赏