문제

I'm trying to perform some HEAD checks using System.Net.Http.HttpClient. It works great on everything except 301 redirects. In that case, HttpClient says the status 200, even though the server said 301 and gave a new Location.

Here's a quick test to validate what I'm seeing:

[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
    }
}

Output from the above is:

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

I know the server is saying 301 because a quick HEAD check using Advanced REST Client to test http://www.youtube.com/ says:

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

I did find this answer, Using HttpClient, how would I prevent automatic redirects and get original status code and forwading Url in the case of 301, however my results are different.

도움이 되었습니까?

해결책

I tried doing a win32 pinvoke version of this as well and I still get 200 OK as status code. But I did find this answer and it should work. http://mail-archives.apache.org/mod_mbox/hc-dev/200501.mbox/%3CA68B76BAB1C27346BE22FED8D74ACE2C0283BB@owm-exc-1.telecomsys.com%3E

Below is the pinvoke code I used for research if you want to see :

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);
            }
        }
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top