Files
KinginfoGateway/src/Admin/ThingsGateway.Furion/V5_Experience/HttpRemote/Extensions/HttpContextExtensions.cs
2025-10-09 19:05:33 +08:00

746 lines
34 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ------------------------------------------------------------------------
// 版权信息
// 版权归百小僧及百签科技(广东)有限公司所有。
// 所有权利保留。
// 官方网站https://baiqian.com
//
// 许可证信息
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System.Net.Http.Headers;
using ThingsGateway.Extension;
namespace ThingsGateway.HttpRemote.Extensions;
/// <summary>
/// <see cref="HttpContext" /> 拓展类
/// </summary>
public static partial class HttpContextExtensions
{
/// <summary>
/// 忽略在转发时需要跳过的响应标头列表
/// </summary>
/// <remarks>
/// <list type="bullet">
/// <item>
/// <term>Content-Type: </term>
/// <description>
/// 非标准的 <c>Content-Type</c> 值(例如 <c>text/plain; charset=utf-8</c>
/// 可能会导致“No output formatter was found for content types 'text/plain; charset=utf-8, text/plain;
/// charset=utf-8' to write the response.”错误。忽略此标头以防止此类错误。
/// </description>
/// </item>
/// <item>
/// <term>Transfer-Encoding: </term>
/// <description>当响应标头包含 <c>Transfer-Encoding: chunked</c> 时,可能导致响应处理过程无限期挂起。忽略此标头可避免该问题。</description>
/// </item>
/// </list>
/// </remarks>
internal static readonly HashSet<string> _ignoreResponseHeaders =
[
"Content-Type", "Connection", "Transfer-Encoding", "Keep-Alive", "Upgrade", "Proxy-Connection"
];
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
public static HttpResponseMessage? Forward(this HttpContext? httpContext, string? requestUri = null,
Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
Forward(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method),
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute), configure,
completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
public static HttpResponseMessage? Forward(this HttpContext? httpContext, HttpMethod httpMethod,
string? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
Forward(httpContext, httpMethod,
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute), configure,
completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
public static HttpResponseMessage? Forward(this HttpContext? httpContext, Uri? requestUri = null,
Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
Forward(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method), requestUri,
configure, completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
public static HttpResponseMessage? Forward(this HttpContext? httpContext, HttpMethod httpMethod,
Uri? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpContext);
ArgumentNullException.ThrowIfNull(httpMethod);
// 初始化转发所需的服务
var (httpContextForwardBuilder, httpRequestBuilder, httpRemoteService) =
PrepareForwardService(httpContext, httpMethod, requestUri, configure, forwardOptions);
// 发送 HTTP 远程请求
var httpResponseMessage =
httpRemoteService.Send(httpRequestBuilder, completionOption, httpContext.RequestAborted);
// 根据配置选项将 HttpResponseMessage 信息转发到 HttpContext 中
ForwardResponseMessage(httpContext, httpResponseMessage, httpContextForwardBuilder.ForwardOptions);
return httpResponseMessage;
}
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
public static Task<HttpResponseMessage?> ForwardAsync(this HttpContext? httpContext, string? requestUri = null,
Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
ForwardAsync(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method),
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute), configure,
completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
public static Task<HttpResponseMessage?> ForwardAsync(this HttpContext? httpContext, HttpMethod httpMethod,
string? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
ForwardAsync(httpContext, httpMethod,
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute), configure,
completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
public static Task<HttpResponseMessage?> ForwardAsync(this HttpContext? httpContext, Uri? requestUri = null,
Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
ForwardAsync(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method), requestUri,
configure, completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
public static async Task<HttpResponseMessage?> ForwardAsync(this HttpContext? httpContext, HttpMethod httpMethod,
Uri? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpContext);
ArgumentNullException.ThrowIfNull(httpMethod);
// 初始化转发所需的服务
var (httpContextForwardBuilder, httpRequestBuilder, httpRemoteService) =
await PrepareForwardServiceAsync(httpContext, httpMethod, requestUri, configure, forwardOptions).ConfigureAwait(false);
// 发送 HTTP 远程请求
var httpResponseMessage = await httpRemoteService.SendAsync(httpRequestBuilder, completionOption,
httpContext.RequestAborted).ConfigureAwait(false);
// 根据配置选项将 HttpResponseMessage 信息转发到 HttpContext 中
ForwardResponseMessage(httpContext, httpResponseMessage, httpContextForwardBuilder.ForwardOptions);
return httpResponseMessage;
}
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <typeparam name="TResult">转换的目标类型</typeparam>
/// <returns>
/// <see cref="HttpRemoteResult{TResult}" />
/// </returns>
public static HttpRemoteResult<TResult>? Forward<TResult>(this HttpContext? httpContext, string? requestUri = null,
Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
Forward<TResult>(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method),
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute), configure,
completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <typeparam name="TResult">转换的目标类型</typeparam>
/// <returns>
/// <see cref="HttpRemoteResult{TResult}" />
/// </returns>
public static HttpRemoteResult<TResult>? Forward<TResult>(this HttpContext? httpContext, HttpMethod httpMethod,
string? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
Forward<TResult>(httpContext, httpMethod,
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute), configure,
completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <typeparam name="TResult">转换的目标类型</typeparam>
/// <returns>
/// <see cref="HttpRemoteResult{TResult}" />
/// </returns>
public static HttpRemoteResult<TResult>? Forward<TResult>(this HttpContext? httpContext, Uri? requestUri = null,
Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
Forward<TResult>(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method), requestUri,
configure, completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <typeparam name="TResult">转换的目标类型</typeparam>
/// <returns>
/// <see cref="HttpRemoteResult{TResult}" />
/// </returns>
public static HttpRemoteResult<TResult>? Forward<TResult>(this HttpContext? httpContext, HttpMethod httpMethod,
Uri? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpContext);
ArgumentNullException.ThrowIfNull(httpMethod);
// 初始化转发所需的服务
var (httpContextForwardBuilder, httpRequestBuilder, httpRemoteService) =
PrepareForwardService(httpContext, httpMethod, requestUri, configure, forwardOptions);
// 发送 HTTP 远程请求
var result = httpRemoteService.Send<TResult>(httpRequestBuilder, completionOption, httpContext.RequestAborted);
// 根据配置选项将 HttpResponseMessage 信息转发到 HttpContext 中
ForwardResponseMessage(httpContext, result?.ResponseMessage, httpContextForwardBuilder.ForwardOptions);
return result;
}
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <typeparam name="TResult">转换的目标类型</typeparam>
/// <returns>
/// <see cref="HttpRemoteResult{TResult}" />
/// </returns>
public static Task<HttpRemoteResult<TResult>?> ForwardAsync<TResult>(this HttpContext? httpContext,
string? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
ForwardAsync<TResult>(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method),
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute), configure,
completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <typeparam name="TResult">转换的目标类型</typeparam>
/// <returns>
/// <see cref="HttpRemoteResult{TResult}" />
/// </returns>
public static Task<HttpRemoteResult<TResult>?> ForwardAsync<TResult>(this HttpContext? httpContext,
HttpMethod httpMethod, string? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
ForwardAsync<TResult>(httpContext, httpMethod,
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute), configure,
completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <typeparam name="TResult">转换的目标类型</typeparam>
/// <returns>
/// <see cref="HttpRemoteResult{TResult}" />
/// </returns>
public static Task<HttpRemoteResult<TResult>?> ForwardAsync<TResult>(this HttpContext? httpContext,
Uri? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null) =>
ForwardAsync<TResult>(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method), requestUri,
configure, completionOption, forwardOptions);
/// <summary>
/// 转发 <see cref="HttpContext" /> 到新的 HTTP 远程地址
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="completionOption">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <typeparam name="TResult">转换的目标类型</typeparam>
/// <returns>
/// <see cref="HttpRemoteResult{TResult}" />
/// </returns>
public static async Task<HttpRemoteResult<TResult>?> ForwardAsync<TResult>(this HttpContext? httpContext,
HttpMethod httpMethod, Uri? requestUri = null, Action<HttpRequestBuilder>? configure = null,
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead,
HttpContextForwardOptions? forwardOptions = null)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpContext);
ArgumentNullException.ThrowIfNull(httpMethod);
// 初始化转发所需的服务
var (httpContextForwardBuilder, httpRequestBuilder, httpRemoteService) =
await PrepareForwardServiceAsync(httpContext, httpMethod, requestUri, configure, forwardOptions).ConfigureAwait(false);
// 发送 HTTP 远程请求
var result = await httpRemoteService.SendAsync<TResult>(httpRequestBuilder, completionOption,
httpContext.RequestAborted).ConfigureAwait(false);
// 根据配置选项将 HttpResponseMessage 信息转发到 HttpContext 中
ForwardResponseMessage(httpContext, result?.ResponseMessage, httpContextForwardBuilder.ForwardOptions);
return result;
}
/// <summary>
/// 创建 <see cref="HttpContextForwardBuilder" /> 实例
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpContextForwardBuilder" />
/// </returns>
public static HttpContextForwardBuilder CreateForwardBuilder(this HttpContext? httpContext, HttpMethod httpMethod,
string? requestUri = null, HttpContextForwardOptions? forwardOptions = null) =>
CreateForwardBuilder(httpContext, httpMethod,
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute),
forwardOptions);
/// <summary>
/// 创建 <see cref="HttpContextForwardBuilder" /> 实例
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpContextForwardBuilder" />
/// </returns>
public static HttpContextForwardBuilder CreateForwardBuilder(this HttpContext? httpContext,
string? requestUri = null,
HttpContextForwardOptions? forwardOptions = null) =>
CreateForwardBuilder(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method),
string.IsNullOrWhiteSpace(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute),
forwardOptions);
/// <summary>
/// 创建 <see cref="HttpContextForwardBuilder" /> 实例
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpContextForwardBuilder" />
/// </returns>
public static HttpContextForwardBuilder CreateForwardBuilder(this HttpContext? httpContext, HttpMethod httpMethod,
Uri? requestUri = null, HttpContextForwardOptions? forwardOptions = null) =>
new(httpContext, httpMethod, requestUri, forwardOptions);
/// <summary>
/// 创建 <see cref="HttpContextForwardBuilder" /> 实例
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
/// <returns>
/// <see cref="HttpContextForwardBuilder" />
/// </returns>
public static HttpContextForwardBuilder CreateForwardBuilder(this HttpContext? httpContext, Uri? requestUri = null,
HttpContextForwardOptions? forwardOptions = null) =>
new(httpContext, Helpers.ParseHttpMethod(httpContext?.Request.Method), requestUri, forwardOptions);
/// <summary>
/// 根据配置选项将 <see cref="HttpResponseMessage" /> 信息转发到 <see cref="HttpContext" /> 中
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpResponseMessage">
/// <see cref="HttpResponseMessage" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
internal static void ForwardResponseMessage(HttpContext httpContext, HttpResponseMessage? httpResponseMessage,
HttpContextForwardOptions forwardOptions)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpContext);
ArgumentNullException.ThrowIfNull(forwardOptions);
// 空检查
if (httpResponseMessage is null)
{
// 输出调试信息
Debugging.Error("The response content was not read, as it was empty.");
return;
}
// 获取 HttpResponse 实例
var httpResponse = httpContext.Response;
// 检查是否配置了响应状态码转发
if (forwardOptions.WithResponseStatusCode)
{
httpResponse.StatusCode = (int)httpResponseMessage.StatusCode;
}
// 检查是否配置了响应标头转发
if (forwardOptions.WithResponseHeaders)
{
ForwardHttpHeaders(httpResponse, httpResponseMessage.Headers, forwardOptions);
}
// 检查是否配置了响应内容标头转发
if (forwardOptions.WithResponseContentHeaders)
{
ForwardHttpHeaders(httpResponse, httpResponseMessage.Content.Headers, forwardOptions);
}
// 调用用于在转发响应之前执行自定义操作
forwardOptions.OnForward?.Invoke(httpContext, httpResponseMessage);
}
/// <summary>
/// 转发 HTTP 标头
/// </summary>
/// <param name="httpResponse">
/// <see cref="HttpResponse" />
/// </param>
/// <param name="httpHeaders">
/// <see cref="HttpHeaders" />
/// </param>
/// <param name="forwardOptions">
/// <see cref="HttpContextForwardOptions" />
/// </param>
internal static void ForwardHttpHeaders(HttpResponse httpResponse, HttpHeaders httpHeaders,
HttpContextForwardOptions forwardOptions)
{
// 初始化忽略在转发时需要跳过的响应标头列表
var ignoreResponseHeaders =
_ignoreResponseHeaders.ConcatIgnoreNull(forwardOptions.IgnoreResponseHeaders).Distinct().ToArray();
// 逐条更新响应标头
foreach (var (key, values) in httpHeaders)
{
// 忽略特定响应标头
if (key.IsIn(ignoreResponseHeaders, StringComparer.OrdinalIgnoreCase))
{
continue;
}
httpResponse.Headers[key] = values.ToArray();
}
}
/// <summary>
/// 初始化转发所需的服务
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="forwardOptions">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <returns>
/// <see cref="Tuple" />
/// </returns>
internal static (HttpContextForwardBuilder httpContextForwardBuilder, HttpRequestBuilder httpRequestBuilder,
IHttpRemoteService httpRemoteService) PrepareForwardService(HttpContext httpContext, HttpMethod httpMethod,
Uri? requestUri, Action<HttpRequestBuilder>? configure = null,
HttpContextForwardOptions? forwardOptions = null)
{
// 创建 HttpContextForwardBuilder 实例
var httpContextForwardBuilder = CreateForwardBuilder(httpContext, httpMethod, requestUri, forwardOptions);
// 构建 HttpRequestBuilder 实例
var httpRequestBuilder = httpContextForwardBuilder.Build(configure);
// 获取 IHttpRemoteService 实例
var httpRemoteService = httpContext.RequestServices.GetRequiredService<IHttpRemoteService>();
return (httpContextForwardBuilder, httpRequestBuilder, httpRemoteService);
}
/// <summary>
/// 初始化转发所需的服务
/// </summary>
/// <param name="httpContext">
/// <see cref="HttpContext" />
/// </param>
/// <param name="httpMethod">转发方式</param>
/// <param name="requestUri">转发地址。若为空则尝试从请求标头 <c>X-Forward-To</c> 中获取目标地址。</param>
/// <param name="configure">自定义配置委托</param>
/// <param name="forwardOptions">
/// <see cref="HttpCompletionOption" />
/// </param>
/// <returns>
/// <see cref="Tuple" />
/// </returns>
internal static async
Task<(HttpContextForwardBuilder httpContextForwardBuilder, HttpRequestBuilder httpRequestBuilder,
IHttpRemoteService
httpRemoteService)> PrepareForwardServiceAsync(HttpContext httpContext, HttpMethod httpMethod,
Uri? requestUri,
Action<HttpRequestBuilder>? configure = null, HttpContextForwardOptions? forwardOptions = null)
{
// 创建 HttpContextForwardBuilder 实例
var httpContextForwardBuilder = CreateForwardBuilder(httpContext, httpMethod, requestUri, forwardOptions);
// 构建 HttpRequestBuilder 实例
var httpRequestBuilder = await httpContextForwardBuilder.BuildAsync(configure).ConfigureAwait(false);
// 获取 IHttpRemoteService 实例
var httpRemoteService = httpContext.RequestServices.GetRequiredService<IHttpRemoteService>();
return (httpContextForwardBuilder, httpRequestBuilder, httpRemoteService);
}
}