Приложение, работающее в эмуляторе Android, не может выполнить HTTP-публикацию на localhost - PullRequest
0 голосов
/ 23 октября 2019

Я не могу выполнить HTTP Post с приложением, запущенным в Эмуляторе Android .

{StatusCode: 400, ReasonPhrase: 'Неверный запрос ', Версия: 1.1, Содержимое: System.Net.Http.HttpConnection + HttpConnectionResponseContent, Заголовки: {Сервер: Microsoft-HTTPAPI / 2.0 Дата: среда, 23 октября 2019 00:58:01 GMT Соединение: закрыть Переадресовано: хост =XXX.XXX.X.XX: ХХХХХ;proto = https Content-Type: text / html;charset = us-ascii
Content-Length: 374}}

Настройка:

  • Я использую IP-адрес, сгенерированный Конвейер по Keyoti
  • Я установил сертификат безопасности на эмуляторе, необходимый для Конвейер по Keyoti
  • Я поменял Microsoft.AspNetCore.Mvc.HttpPostатрибут с System.Web.Http.HttpPost

Эмулятор:

  • Успешно: HTTP Get
  • Сбой: HTTP Post

Интеграционный тест:

  • Успешно: HTTP Post (с использованием той же конечной точки)

Код:

Я написал автоматический тест, который вызывает ту же реализацию HTTP Post. Поскольку я успешно выполнил тот же код на своем ноутбуке с помощью автоматического теста, я не думаю, что проблема заключается в реальном коде:

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

        ...

Резюме:

В заключение я выделил среду для эмулятора Android, а не для своего ноутбука. Следовательно, эмулятор может успешно запустить HTTP Get. Однако он не может выполнить HTTP-публикацию, даже если мое портативное устройство может выполнять оба действия.

ОБНОВЛЕНИЕ:

Я применил руководство из этого Xamarin Android ASP. Net Core WebAPI document .

В частности, я установил еще один сертификат безопасности на эмуляторе Android.

Затем я смог наблюдать HTTP Get на эмуляторе Android.

Тем не менее, я продолжаю получать сообщение об ошибке HTTP Post.

OperationCanceledException

Физическое устройство:

Если я запускаю приложение с физического устройства Android, я наблюдаюследующее:

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

Новое обновление:

Я отключил отладку только для своего кода в реализации сервера и обнаружил следующее исключение:

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

Есть предложения?

Ответы [ 3 ]

0 голосов
/ 30 октября 2019

это может быть не прямой ответ на ваш вопрос, но я хотел бы предложить localtunnel . очень простой способ временно выставить локальный API, чтобы вы могли проверить его на эмуляторе или даже на физическом устройстве. Я использовал это много себя, так как очень удобно просто набрать одну строку в терминале, чтобы запустить его.

0 голосов
/ 31 октября 2019

Следующая ссылка решила мою проблему.

Инфраструктура:

type GlobalHttpClient private () =

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

    static member val Instance = httpClient with get,set

Проект Xamarin.Android:

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:

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

Клиентский шлюз:

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
0 голосов
/ 23 октября 2019

Похоже, у вас .NET Core Api. .NET Core не имеет System.Web в Asp.NET. Атрибут HttpPost и HttpGet должны исходить из открытого пространства имен Microsoft.AspNetCore.Mvc.

Кроме того, поскольку вы используете привязку модели атрибута ApiController, она будет работать до тех пор, пока вы привязываетесь к модели, а не просто к строке json.

Создайте модель, к которой нужно привязать json, и используйте этот тип для параметра в Post и удалите атрибут FromBody. Также, если вы делаете это, вам, вероятно, не нужен newtonsoft.json.

open Microsoft.AspNetCore.Mvc

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

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