我正在嘗試創建一個 webhook 來接收來自 Twilio 電話號碼的訊息。但是,我需要這個 webhook 將 Twilio 的訊息傳遞到內部 API,等待回應,然后將結果回傳給 Twilio,而不是只需要一個可以修改資料并立即將結果回傳給 Twilio 的 webhook。
這是我想出的一些通用代碼,我希望它可以作業。
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;
}
此代碼的問題在于 TwilioUnsupported Media Type在進入函式之前立即回傳 415 錯誤代碼 ( )。
當我嘗試接受“正確的型別”(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;
}
- 我能做些什么來“屏蔽”函式的接受型別或保持第一個函式通用嗎?
- 如何將此 SmsRequest 推回“表單編碼”物件,以便我可以在消費服務中以相同的方式接受它?
uj5u.com熱心網友回復:
TLDR 您的選擇是:
- 使用現有的反向代理,如 NGINX、HAProxy、F5
- 使用 YARP 向 ASP.NET Core 專案添加反向代理功能
- 在控制器中接受 webhook 請求,將標頭和資料映射到新的
HttpRequestMessage并將其發送到您的私有服務,然后將您的私有服務的回應映射回 Twilio 的回應。
聽起來您要構建的是反向代理。在您的 Web 應用程式前面放置一個反向代理是很常見的,用于 SSL 終止、快取、基于主機名或 URL 的路由等。反向代理將接收 Twilio HTTP 請求,然后將其轉發到正確的私有服務。私有服務回應反向代理轉發回 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 webhook 請求,并將所有標頭和內容轉發到私有 Web 服務。請注意,即使我能夠一起破解它直到它起作用,它也可能不安全且性能不佳。您可能需要做更多作業才能使其成為生產級代碼。使用風險自負。
在私有服務的 ASP.NET Core 專案中,使用 aTwilioController接受請求:
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);
}
}
Instead of proxying the request using the brittle code in the reverse proxy controller, I'd recommend installing YARP in your reverse proxy project, which is an ASP.NET Core based reverse proxy library.
dotnet add package Yarp.ReverseProxy
Then add the following configuration to appsettings.json:
{
...
"ReverseProxy": {
"Routes": {
"SmsRoute" : {
"ClusterId": "SmsCluster",
"Match": {
"Path": "/sms"
}
}
},
"Clusters": {
"SmsCluster": {
"Destinations": {
"SmsService1": {
"Address": "https://localhost:7196"
}
}
}
}
}
}
This configuration will forward any request to the path /Sms, to your private ASP.NET Core service, which on my local machine is running at https://localhost:7196.
You also need to update your Program.cs file to start using YARP:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();
When you run both projects now, the Twilio webhook request to /sms is forwarded to your private service, your private service will respond, and your reverse proxy service will forward the response back to Twilio.
Using YARP you can do a lot more through configuration or even programmatically, so if you're interested I'd check out the YARP docs.
If you already have a reverse proxy like NGINX, HAProxy, F5, etc. it may be easier to configure that to forward your request instead of using YARP.
PS: Here's the source code for the hacky and YARP solution
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/457051.html
