Общая передача/пересылка данных формы в ApsNet.Core

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

Вот некоторый общий код, который я придумал, и я надеялся, что он будет работать.

public async Task<HttpResponseMessage> ReceiveAndForwardSms(HttpContent smsContent)
        {
            var client = new HttpClient();
            
            HttpResponseMessage response = await client.PostAsync(Environment.GetEnvironmentVariable("requestUriBase") + "/api/SmsHandler/PostSms", smsContent);
            
            return response;
        }

Проблема с этим кодом в том, что Twilio сразу возвращает код ошибки 415 (Unsupported Media Type) перед входом в функцию.

Когда я пытаюсь принять «правильный тип» (Twilio.AspNet.Common.SmsRequest), я не могу вставить SmsRequest обратно в объект, закодированный формой, и отправить его через client.PostAsync()... Бывший.:

public async Task<HttpResponseMessage> ReceiveAndForwardSms([FromForm]SmsRequest smsRequest)
{
    var client = new HttpClient();
    var stringContent = new StringContent(smsRequest.ToString());
    
    HttpResponseMessage response = await client.PostAsync(Environment.GetEnvironmentVariable("requestUriBase") + "/api/SmsHandler/PostSms", stringContent);
    return response;
}
  1. Есть ли что-нибудь, что я могу сделать, чтобы «замаскировать» принятый тип функции или сохранить эту первую функцию общей?
  2. Как мне поместить этот SmsRequest обратно в объект «закодированный формой», чтобы я мог принять его таким же образом в моей потребляющей службе?
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

TLDR Ваши варианты:

  • Используйте существующий обратный прокси-сервер, например NGINX, HAProxy, F5.
  • Используйте YARP для добавления функции обратного прокси-сервера в проект ASP.NET Core.
  • Примите запрос веб-перехватчика в контроллере, сопоставьте заголовки и данные с новым HttpRequestMessage и отправьте его в свою частную службу, затем сопоставьте ответ вашей частной службы с ответом обратно в Twilio.

Похоже, вы пытаетесь построить обратный прокси. Очень часто перед вашим веб-приложением помещают обратный прокси-сервер для терминации SSL, кэширования, маршрутизации на основе имени хоста или URL-адреса и т. д. Обратный прокси-сервер получит HTTP-запрос Twilio, а затем перенаправит его в нужную частную службу. Частный сервис отвечает, и обратный прокси-сервер перенаправляет его обратно в Twilio.

Я бы порекомендовал использовать существующий обратный прокси вместо того, чтобы создавать эту функциональность самостоятельно. Если вы действительно хотите создать его самостоятельно, вот пример, который мне удалось заставить работать:

В вашем обратном прокси-проекте добавьте контроллер как таковой:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;

namespace ReverseProxy.Controllers;

public class SmsController : Controller
{
    private static readonly HttpClient HttpClient;
    private readonly ILogger<SmsController> logger;
    private readonly string twilioWebhookServiceUrl;

    static SmsController()
    {
        // don't do this in production!
        var insecureHttpClientHandler = new HttpClientHandler();
        insecureHttpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true;
        HttpClient = new HttpClient(insecureHttpClientHandler);
    }

    public SmsController(ILogger<SmsController> logger, IConfiguration configuration)
    {
        this.logger = logger;
        twilioWebhookServiceUrl = configuration["TwilioWebhookServiceUrl"];
    }

    public async Task Index()
    {
        using var serviceRequest = new HttpRequestMessage(HttpMethod.Post, twilioWebhookServiceUrl);
        foreach (var header in Request.Headers)
        {
            serviceRequest.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
        }
        
        serviceRequest.Content = new FormUrlEncodedContent(
            Request.Form.ToDictionary(
                kv => kv.Key,
                kv => kv.Value.ToString()
            )
        );
        
        var serviceResponse = await HttpClient.SendAsync(serviceRequest);

        Response.ContentType = "application/xml";
        var headersDenyList = new HashSet<string>()
        {
            "Content-Length",
            "Date",
            "Transfer-Encoding"
        };
        foreach (var header in serviceResponse.Headers)
        {
            if (headersDenyList.Contains(header.Key)) continue;
            logger.LogInformation("Header: {Header}, Value: {Value}", header.Key, string.Join(',', header.Value));
            Response.Headers.Add(header.Key, new StringValues(header.Value.ToArray()));
        }

        await serviceResponse.Content.CopyToAsync(Response.Body);
    }
}

Это примет запрос веб-перехватчика Twilio и перенаправит все заголовки и содержимое в частную веб-службу. Имейте в виду, хотя мне удалось взломать это, пока оно не заработает, оно, вероятно, небезопасно и неэффективно. Вам, вероятно, придется сделать гораздо больше, чтобы это стало кодом производственного уровня. Используйте на свой риск.

В проекте ASP.NET Core для вашей частной службы используйте TwilioController, чтобы принять запрос:

using Microsoft.AspNetCore.Mvc;
using Twilio.AspNet.Common;
using Twilio.AspNet.Core;
using Twilio.TwiML;

namespace Service.Controllers;

public class SmsController : TwilioController
{
    private readonly ILogger<SmsController> logger;

    public SmsController(ILogger<SmsController> logger)
    {
        this.logger = logger;
    }

    public IActionResult Index(SmsRequest smsRequest)
    {
        logger.LogInformation("SMS Received: {SmsId}", smsRequest.SmsSid);
        var response = new MessagingResponse();
        response.Message($"You sent: {smsRequest.Body}");
        return TwiML(response);
    }
}

Вместо того, чтобы проксировать запрос с использованием хрупкого кода в обратном прокси-контроллере, я бы рекомендовал установить YARP в ваш проект обратного прокси, который представляет собой библиотеку обратного прокси на основе ASP.NET Core.

dotnet add package Yarp.ReverseProxy

Затем добавьте следующую конфигурацию в appsettings.json:

{
  ...
  "ReverseProxy": {
    "Routes": {
      "SmsRoute" : {
        "ClusterId": "SmsCluster",
        "Match": {
          "Path": "/sms"
        }
      }
    },
    "Clusters": {
      "SmsCluster": {
        "Destinations": {
          "SmsService1": {
            "Address": "https://localhost:7196"
          }
        }
      }
    }
  }
}

Эта конфигурация будет перенаправлять любой запрос по пути /Смс в вашу частную службу ASP.NET Core, которая на моем локальном компьютере работает по адресу https://локальный: 7196.

Вам также необходимо обновить файл Программа.cs, чтобы начать использовать YARP:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();

Когда вы сейчас запустите оба проекта, запрос веб-перехватчика Twilio к /смс будет переадресован вашей частной службе, ваша частная служба ответит, а служба обратного прокси-сервера перешлет ответ обратно в Twilio.

Используя YARP, вы можете сделать гораздо больше с помощью конфигурации или даже программно, поэтому, если вам интересно, я бы проверил файл Ярп документы.

Если у вас уже есть обратный прокси-сервер, такой как NGINX, HAProxy, F5 и т. д., может быть проще настроить его для пересылки вашего запроса вместо использования YARP.

PS: вот исходный код решения для взлома и YARP

Я надеюсь, что это понятно, если не ЛМК, и я сделаю все возможное, чтобы прояснить.

Swimburger 06.04.2022 02:45

Круто, спасибо за подробный ответ (и предупреждения... Я бы сделал это в продакшене, если бы не было сказано не LOL). IDK, почему я думал, что будет существовать универсальное, короткое и простое решение для переадресации, которое будет легко реализовать.

Skewjo 06.04.2022 13:38

Другие вопросы по теме