2014-04-01 111 views
3

我試圖執行一些HEAD檢查使用System.Net.Http.HttpClient。除了301重定向之外,它對所有內容都很有用。在這種情況下,即使服務器說301並給了一個新的位置,HttpClient也會說狀態200。HttpClient忽略AllowAutoRedirect指令

這裏有一個快速測試來驗證我所看到的:

[Test] 
public async void Test301Capture() 
{ 
    const string url = "http://www.youtube.com/"; // http://www.youtube.com/ does a 301 to https://www.youtube.com/ 

    var httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = false }; 

    using (var client = new HttpClient(httpClientHandler)) 
    using (var headRequest = new HttpRequestMessage(HttpMethod.Head, url)) 
    using (var headResponse = await client.SendAsync(headRequest)) 
    { 
     Log.InfoFormat("Result of HEAD check on \"{0}\" is: {1}", url, headResponse.StatusCode); // *should* be a 301 
     Assert.AreNotEqual(200, (int)headResponse.StatusCode); // *fails* because StatusCode *is* 200 
    } 
} 

從上面的輸出是:

Result of HEAD check on "http://www.youtube.com/" is: OK 

我知道服務器是因爲使用先進的快速頭顱檢查說301 REST客戶端測試http://www.youtube.com/說:

Redirect 
To:https://www.youtube.com/ with status: 301 Show explanation HTTP/1.1 301 Moved Permanently 
Redirection information has not been cached. 
Date: Tue, 01 Apr 2014 20:08:09 GMT 
Server: gwiseguy/2.0 
Content-Length: 0 
Cache-Control: no-cache 
X-Content-Type-Options: nosniff 
Content-Type: text/html; charset=utf-8 
Expires: Tue, 27 Apr 1971 19:44:06 EST 
X-XSS-Protection: 1; mode=block; report=https://www.google.com/appserve/security-bugs/log/youtube 
Location: https://www.youtube.com/ 
Alternate-Protocol: 80:quic 

我沒有找到這個答案,Using HttpClient, how would I prevent automatic redirects and get original status code and forwading Url in the case of 301,但是我的結果是不同的。

+1

結果:與PInvoke的@kyleb的經驗,並用自己的使用測試.NET插座(和野生野兔刺傷Python)說服我,301s的自動重定向被烘焙到Windows的低級聯網中。 – Bex

回答

0

我試着做一個win32的pinvoke版本以及我仍然得到200 OK作爲狀態碼。但我確實找到了這個答案,它應該起作用。 http://mail-archives.apache.org/mod_mbox/hc-dev/200501.mbox/%[email protected]m%3E

下面是我用於研究的PInvoke的代碼,如果你想看到:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading.Tasks; 

namespace HttpTest 
{ 
    class Program 
    { 
     const int INTERNET_OPEN_TYPE_DIRECT = 1;  // direct to net 
     const short INTERNET_DEFAULT_HTTP_PORT = 80; 
     const int INTERNET_SERVICE_HTTP = 3; 

     const uint INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP = 0x00008000; 

     const uint INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS = 0x00004000; 
     const uint INTERNET_FLAG_KEEP_CONNECTION = 0x00400000; 
     const uint INTERNET_FLAG_NO_AUTH = 0x00040000; 
     const uint INTERNET_FLAG_NO_AUTO_REDIRECT = 0x00200000; 
     const uint INTERNET_FLAG_NO_COOKIES = 0x00080000; 
     const uint INTERNET_FLAG_NO_UI = 0x00000200; 
     const uint INTERNET_FLAG_RELOAD = 0x80000000; 

     const int HTTP_QUERY_STATUS_CODE = 19; 

     [DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)] 
     static extern IntPtr InternetOpen(string lpszAgent, int dwAccessType, string lpszProxyName, string lpszProxyBypass, int dwFlags); 

     [DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)] 
     static extern IntPtr InternetConnect(IntPtr hInternet, string lpszServerName, short nServerPort, string lpszUsername, string lpszPassword, int dwService, int dwFlags, IntPtr dwContext); 

     [DllImport("wininet.dll", SetLastError = true)] 
     static extern IntPtr HttpOpenRequest(
      IntPtr hConnect, 
      string lpszVerb, 
      string lpszObjectName, 
      string lpszVersion, 
      string lpszReferer, 
      string[] lplpszAcceptTypes, 
      uint dwFlags, 
      IntPtr dwContext); 

     [DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)] 
     static extern bool HttpSendRequest(IntPtr hRequest, IntPtr lpszHeaders, uint dwHeadersLength, IntPtr lpOptional, uint dwOptionalLength); 

     [DllImport("wininet.dll", SetLastError = true)] 
     static extern bool HttpQueryInfo(IntPtr hInternet, int dwInfoLevel, IntPtr lpBuffer, ref long lpdwBufferLength, ref long lpdwIndex); 

     static void Main(string[] args) 
     { 
      IntPtr openPtr = InternetOpen("Kyle", INTERNET_OPEN_TYPE_DIRECT, null, null, 0); 
      IntPtr context = IntPtr.Zero; 
      IntPtr connectPtr = InternetConnect(openPtr, "www.youtube.com", INTERNET_DEFAULT_HTTP_PORT, null, null, INTERNET_SERVICE_HTTP, 0, context); 
      IntPtr openRequestPtr = HttpOpenRequest(connectPtr, "GET", "/", null, null, null, 
       INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | 
       INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | 
       INTERNET_FLAG_KEEP_CONNECTION | 
       INTERNET_FLAG_NO_AUTH | 
       INTERNET_FLAG_NO_AUTO_REDIRECT | 
       INTERNET_FLAG_NO_COOKIES | 
       INTERNET_FLAG_NO_UI | 
       INTERNET_FLAG_RELOAD, IntPtr.Zero); 

      if (HttpSendRequest(openRequestPtr, IntPtr.Zero, 0, IntPtr.Zero, 0)) 
      { 
       IntPtr buffer = Marshal.AllocHGlobal(4); long lBufferLen = 4; long lHeaderIndex = 0; 
       HttpQueryInfo(openRequestPtr, HTTP_QUERY_STATUS_CODE, buffer, ref lBufferLen, ref lHeaderIndex); 
       string str2 = Marshal.PtrToStringAnsi(buffer); 
      } 
     } 
    } 
}