【问题标题】:Handling HTTP 302 with HttpClient on WP8在 WP8 上使用 HttpClient 处理 HTTP 302
【发布时间】:2014-03-11 20:48:00
【问题描述】:

我正在为 Windows Phone 8 开发的应用程序面临一个非常复杂的问题。以下端点 - http://speedmeter3.internetprovsechny.cz:81/ping/ - 可用于测量连接客户端的延迟。结果存储为 JSON 字符串并返回。但是,为了执行测量,使用了几个 HTTP 302(找到)重定向​​(总是返回到相同的 URL)。结果在浏览器中正确返回,我已经看到了许多在 Android 上解决类似问题的方法,但没有发现在 Windows Phone 上有效。 这是我应该返回字符串的简单代码 sn-p:

HttpClientHandler handler = new HttpClientHandler();
handler.AllowAutoRedirect = true;     
HttpClient client = new HttpClient( handler );
string url = "http://speedmeter3.internetprovsechny.cz:81/ping/";
return await client.GetStringAsync( new Uri( url, UriKind.Absolute ) );

这段代码在 GetStringAsync 方法上挂了一段时间,最终以异常终止:

System.Net.Http.HttpRequestException: Response status code does not indicate success: 302 (Found).
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at IPVSpeedmeter.Helpers.RestClient.<SendGetSafe>d__8.MoveNext()}    System.Exception {System.Net.Http.HttpRequestException}

任何能够为此提供解决方案的人都将在可能的情况下获得赏金(三天后;-))。

谢谢大家

【问题讨论】:

    标签: c# http windows-phone-8 dotnet-httpclient http-status-code-302


    【解决方案1】:

    我猜也许 Win8 的实现并没有阻止自动重定向。这是我使用的重定向处理程序:

        public class GlobalRedirectHandler : DelegatingHandler {
    
        public GlobalRedirectHandler(HttpMessageHandler innerHandler) {
           InnerHandler = innerHandler;
        } 
    
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
            var tcs = new TaskCompletionSource<HttpResponseMessage>();
    
            base.SendAsync(request, cancellationToken)
                .ContinueWith(t => {
                    HttpResponseMessage response;
                    try {
                        response = t.Result;
                    }
                    catch (Exception e) {
                        response = new HttpResponseMessage(HttpStatusCode.ServiceUnavailable);
                        response.ReasonPhrase = e.Message;
                    }
                    if (response.StatusCode == HttpStatusCode.MovedPermanently
                        || response.StatusCode == HttpStatusCode.Moved
                        || response.StatusCode == HttpStatusCode.Redirect
                        || response.StatusCode == HttpStatusCode.Found
                        || response.StatusCode == HttpStatusCode.SeeOther
                        || response.StatusCode == HttpStatusCode.RedirectKeepVerb
                        || response.StatusCode == HttpStatusCode.TemporaryRedirect
    
                        || (int)response.StatusCode == 308) 
                    {
    
                        var newRequest = CopyRequest(response.RequestMessage);
    
                        if (response.StatusCode == HttpStatusCode.Redirect 
                            || response.StatusCode == HttpStatusCode.Found
                            || response.StatusCode == HttpStatusCode.SeeOther)
                        {
                            newRequest.Content = null;
                            newRequest.Method = HttpMethod.Get;
    
                        }
                        newRequest.RequestUri = response.Headers.Location;
    
                        base.SendAsync(newRequest, cancellationToken)
                            .ContinueWith(t2 => tcs.SetResult(t2.Result));
                    }
                    else {
                        tcs.SetResult(response);
                    }
                });
    
            return tcs.Task;
        }
    
        private static HttpRequestMessage CopyRequest(HttpRequestMessage oldRequest) {
            var newrequest = new HttpRequestMessage(oldRequest.Method, oldRequest.RequestUri);
    
            foreach (var header in oldRequest.Headers) {
                newrequest.Headers.TryAddWithoutValidation(header.Key, header.Value);
            }
            foreach (var property in oldRequest.Properties) {
                newrequest.Properties.Add(property);
            }
            if (oldRequest.Content != null) newrequest.Content = new StreamContent(oldRequest.Content.ReadAsStreamAsync().Result);
            return newrequest;
        }
    }
    

    我真的应该清理它以使用 async/await 语法。

    【讨论】:

    • 我明天试试,然后向你汇报:-)。非常感谢!
    • 很抱歉这么晚才回复,但您的解决方案令人难以置信,而且效果很好。太感谢了!我会奖励你 200 赏金,但他们说我必须等待 24 小时才能这样做:-D .
    • @MZetko 不用担心,我不需要代表。很高兴它对你有用。
    • 我认为你的回答真的值得。反正我已经开始赏金了 ;-) .
    • 我们只需要在 Httpclient 对象中使用它作为处理程序吗?
    【解决方案2】:

    我偶然发现了一个类似的问题,但与HttpClient 没有从https 重定向到http 站点有关。这似乎是设计使然 (See GitHub issue)。

    但是,即使重定向不安全,我也要求 http 客户端遵循重定向,所以这是我得到的一个解决方案,它与 Darrel Miller 非常相似。

    public class RedirectHandler : DelegatingHandler
    {
        private static readonly HttpStatusCode[] RedirectOn = {
            HttpStatusCode.MovedPermanently,
            HttpStatusCode.Found
        };
    
        public RedirectHandler(HttpMessageHandler innerHandler)
        {
            InnerHandler = innerHandler;
        }
    
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var response = await base.SendAsync(request, cancellationToken)
                .ConfigureAwait(false);
    
            if (request.Method == HttpMethod.Get && RedirectOn.Contains(response.StatusCode))
            {
                request.RequestUri = response.Headers.Location;
    
                return await base.SendAsync(request, cancellationToken)
                    .ConfigureAwait(false);
            }
    
            return response;
        }
    }
    

    这可以被以下人员使用:

    var client = new HttpClient(new RedirectHandler(new HttpClientHandler()))
    

    【讨论】:

      猜你喜欢
      • 2020-04-27
      • 2013-09-13
      • 1970-01-01
      • 2018-07-15
      • 2016-09-20
      • 1970-01-01
      • 1970-01-01
      • 2013-09-15
      • 1970-01-01
      相关资源
      最近更新 更多