App running in Android Emulator fails to perform an HTTP Post to localhost

拥有回忆 提交于 2019-12-12 06:56:32

问题


I'm unable to perform an HTTP Post with an app running in an Android Emulator.

{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.HttpConnection+HttpConnectionResponseContent, Headers: { Server: Microsoft-HTTPAPI/2.0 Date: Wed, 23 Oct 2019 00:58:01 GMT Connection: close Forwarded: host=XXX.XXX.X.XX:XXXXX; proto=https Content-Type: text/html; charset=us-ascii
Content-Length: 374 }}

Setup:

  • I'm using an IP address generated by Conveyor by Keyoti
  • I installed a security certificate on the emulator required by Conveyor by Keyoti
  • I swapped out Microsoft.AspNetCore.Mvc.HttpPost attribute with System.Web.Http.HttpPost

Emulator:

  • Successful: HTTP Get
  • Failed: HTTP Post

Integration Test:

  • Successful: HTTP Post (using same endpoint)

Code:

I wrote an automated test that calls the same HTTP Post implementation. Because I executed the same code successfully on my laptop via an automated test, I don't think the actual code is the issue:

open Microsoft.AspNetCore.Mvc
open Newtonsoft.Json

[<ApiController>]
[<Route("api/[controller]")>]
type RegisterController () =
    inherit ControllerBase()

    [<System.Web.Http.HttpPost>]
    member x.Post([<FromBody>] json:string) =

        ...

Summary:

In conclusion, I have isolated the environment to the Android Emulator and not my laptop. Hence, the emulator can successfully trigger an HTTP Get. However, it fails to perform a HTTP Post even though my laptop device can do both.

UPDATE:

I applied guidance from this Xamarin Android ASP.Net Core WebAPI document.

Specifically, I installed another security certificate on the Android emulator.

I was then able to observe an HTTP Get on the Android Emulator.

However, I continue to get an error for HTTP Post.

OperationCanceledException

Physical Device:

If I run the app from a physical android device I observe the following:

{StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.HttpConnection+HttpConnectionResponseContent, Headers:
{
  Date: Wed, 23 Oct 2019 13:33:20 GMT
  Server: Kestrel
  Transfer-Encoding: chunked
  Forwarded: host=xxx.xxx.x.xx:xxxxx; proto=https
  Content-Type: text/plain
}}

New Update:

I disabled debugging on just my code on the server implementation and discovered the following exception:

Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: 'Bad chunk size data.'

Any suggestions?


回答1:


this might not be a direct answer to your question, but i would like to suggest localtunnel. a very easy way to temporarily expose your local api so that you can test it either on emulator or even physical device. Have used this alot my self, as it is very convenient to just type a single line in terminal to start it.




回答2:


The following reference solved my issue.

Infrastructure:

type GlobalHttpClient private () =

    static let mutable (httpClient:System.Net.Http.HttpClient) = null

    static member val Instance = httpClient with get,set

Xamarin.Android project:

using Android.Http;
using Android.Net;
using Javax.Net.Ssl;
using System.Net.Http;
using Xamarin.Android.Net;
using Xamarin.Forms;
using WebGatewaySupport;

[assembly: Dependency(typeof(HTTPClientHandlerCreationService_Android))]
namespace Android.Http
{
    public class HTTPClientHandlerCreationService_Android : IHTTPClientHandlerCreationService
    {
        public HttpClientHandler GetInsecureHandler()
        {
            return new IgnoreSSLClientHandler();
        }
    }

    internal class IgnoreSSLClientHandler : AndroidClientHandler
    {
        protected override SSLSocketFactory ConfigureCustomSSLSocketFactory(HttpsURLConnection connection)
        {
            return SSLCertificateSocketFactory.GetInsecure(1000, null);
        }

        protected override IHostnameVerifier GetSSLHostnameVerifier(HttpsURLConnection connection)
        {
            return new IgnoreSSLHostnameVerifier();
        }
    }

    internal class IgnoreSSLHostnameVerifier : Java.Lang.Object, IHostnameVerifier
    {
        public bool Verify(string hostname, ISSLSession session)
        {
            return true;
        }
    }
}

Xamarin.Forms App:

switch (Device.RuntimePlatform)
{
    case Device.Android:
        GlobalHttpClient.Instance = new HttpClient(DependencyService.Get<IHTTPClientHandlerCreationService>().GetInsecureHandler());
        break;

    default:
        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
        GlobalHttpClient.Instance = new HttpClient(new HttpClientHandler());
        break;
}

Client Gateway:

let postTo (baseAddress:string) (resource:string) (payload:Object) =

    GlobalHttpClient.Instance.BaseAddress <- Uri(baseAddress)
    let encoded = Uri.EscapeUriString(resource)

    let result  = GlobalHttpClient.Instance.PostAsJsonAsync(encoded, payload) |> toResult
    result



回答3:


Looks like you have a .NET Core Api. .NET Core does not have System.Web in Asp.NET. The HttpPost attribute and HttpGet attributes should come from Microsoft.AspNetCore.Mvc namespace which you have open.

Also since you are using the ApiController attribute model binding will just work as long as you bind to a model and not just a json string.

Create a model that you want the json to bind to and use that type for your parameter on Post and remove the FromBody attribute. Also if you do that you probably don't need newtonsoft.json.

open Microsoft.AspNetCore.Mvc

[<ApiController>]
[<Route("api/[controller]")>]
type RegisterController () =
    inherit ControllerBase()

    [<HttpPost>]
    member x.Post(thing:TypeOfThing) =


来源:https://stackoverflow.com/questions/58514409/app-running-in-android-emulator-fails-to-perform-an-http-post-to-localhost

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!