简体   繁体   English

在WP8上使用HttpClient处理HTTP 302

[英]Handling HTTP 302 with HttpClient on WP8

I am facing a really complicated problem with the app I am developing for Windows Phone 8. The following endpoint - http://speedmeter3.internetprovsechny.cz:81/ping/ - can be used to measure the latency of connected client. 我为Windows Phone 8开发的应用程序遇到了一个非常复杂的问题。以下端点-http: //speedmeter3.internetprovsechny.cz :81/ ping/ -可用于测量已连接客户端的延迟。 The result is stored as JSON string and is returned. 结果存储为JSON字符串并返回。 However, to perform the measurement, there are several HTTP 302 (Found) redirects used (always returning to the same URL). 但是,为了执行测量,使用了多个HTTP 302(已找到)重定向​​(始终返回相同的URL)。 The result is correctly returned in browsers and I have seen numerous ways to solve similar problem on Android, but have found none that works on Windows Phone. 结果可以在浏览器中正确返回,并且我已经看到许多方法可以解决Android上的类似问题,但是没有一种方法可以在Windows Phone上使用。 Here is my simple code snippet that should return the string: 这是我应该返回字符串的简单代码片段:

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 ) );

This code hangs for a while on the GetStringAsync method and eventually terminates with exception: 这段代码在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}

Anyone who is able to provide a solution for this will be awarded a bounty when it will be possible (after three days ;-) ). 只要有可能,任何能够提供解决方案的人都将获得赏金(三天后;-))。

Thank you all 谢谢你们

I'm guessing that maybe the Win8 implementation doesn't impement autoredirects. 我猜想Win8的实现可能不会妨碍自动重定向。 Here is a redirect handler I use: 这是我使用的重定向处理程序:

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

I really should clean it up to use the async/await syntax though. 我确实应该清理它以使用async / await语法。

I stumbled on a similar problem but related to the HttpClient not redirecting from a https to a http site. 我偶然发现了一个类似的问题,但与HttpClient无法从https重定向到http站点有关。 This seems to be by design ( See GitHub issue ). 这似乎是设计使然请参阅GitHub问题 )。

However I require the http client to follow redirects even if they were insecure so here is a solution I got to, which is very similar to Darrel Miller. 但是,我要求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;
    }
}

This can be used by the following: 可以由以下人员使用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM