如何让你的.NET WebAPI程序支持HTTP3?

2024-01-24 18:52
文章标签 程序 支持 net webapi http3

本文主要是介绍如何让你的.NET WebAPI程序支持HTTP3?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下面我将总结构建Http3的经验,以Token Gateway的项目为例,请注意使用Http3之前你需要知道它的限制,

Windows

  • Windows 11 版本 22000 或更高版本/Windows Server 2022。
  • TLS 1.3 或更高版本的连接。

Linux

  • 已安装 libmsquic 包。

实现讲解

首先我们需要拉取我们的代码

git clone https://gitee.com/hejiale010426/Gateway.git
cd Gateway

然后我们打开Program.cs

#region FreeSql类型转换Utils.TypeHandlers.TryAdd(typeof(Dictionary<string, string>), new StringJsonHandler<Dictionary<string, string>>());
Utils.TypeHandlers.TryAdd(typeof(RouteMatchEntity), new StringJsonHandler<RouteMatchEntity>());
Utils.TypeHandlers.TryAdd(typeof(List<DestinationsEntity>), new StringJsonHandler<List<DestinationsEntity>>());
Utils.TypeHandlers.TryAdd(typeof(string[]), new StringJsonHandler<string[]>());#endregionvar builder = WebApplication.CreateBuilder(args);builder.Configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();builder.WebHost.UseKestrel(options =>
{// 配置多个域名证书options.ConfigureHttpsDefaults(adapterOptions =>{adapterOptions.ServerCertificateSelector = (_, name) =>{// 从Certificate服务中获取if (string.IsNullOrEmpty(name) ||!CertificateService.CertificateEntityDict.TryGetValue(name, out var certificate)) return new X509Certificate2();var path = Path.Combine("/data/", certificate.Path);if (File.Exists(path)) return new X509Certificate2(path, certificate.Password);Console.ForegroundColor = ConsoleColor.Red;Console.WriteLine($"证书文件不存在:{path}");Console.ResetColor();throw new Exception($"证书文件不存在:{path}");};});
});builder.WebHost.ConfigureKestrel(kestrel =>
{kestrel.Limits.MaxRequestBodySize = null;kestrel.ListenAnyIP(8081, portOptions =>{portOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;portOptions.UseHttps();});kestrel.ListenAnyIP(8080, portOptions =>{portOptions.Protocols = HttpProtocols.Http1AndHttp2;});
});#region Jwtbuilder.Services.AddAuthorization().AddJwtBearerAuthentication();#endregionbuilder.Services.Configure<KestrelServerOptions>(options =>
{options.Limits.MaxRequestBodySize = int.MaxValue; 
});builder.Services.Configure<FormOptions>(x =>
{x.ValueLengthLimit = int.MaxValue;x.MultipartBodyLengthLimit = int.MaxValue; // if don't set default value is: 128 MBx.MultipartHeadersLengthLimit = int.MaxValue;
});builder.Services.ConfigureHttpJsonOptions(options =>
{options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());options.SerializerOptions.Converters.Add(new JsonDateTimeConverter());
});builder.Services.AddHostedService<GatewayBackgroundService>();builder.Services.AddCors(options =>
{options.AddPolicy("AllowAll",builder => builder.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials());
});builder.Configuration.GetSection(nameof(RequestOptions)).Get<RequestOptions>();
builder.Services.AddMemoryCache();builder.Services.AddSingleton<RequestLogMiddleware>();
builder.Services.AddSingleton<StaticFileProxyMiddleware>();builder.Services.AddSingleton<RequestLogService>();
builder.Services.AddSingleton<GatewayService>();
builder.Services.AddSingleton<CertificateService>();
builder.Services.AddSingleton<FileStorageService>();
builder.Services.AddSingleton<StaticFileProxyService>();
builder.Services.AddSingleton<TestService>();
builder.Services.AddSingleton<SettingService>();
builder.Services.AddSingleton<AuthorityService>();builder.Services.AddSingleton<IContentTypeProvider, FileExtensionContentTypeProvider>();builder.Services.AddSingleton<IFreeSql>(_ =>
{var directory = new DirectoryInfo("/data");if (!directory.Exists){directory.Create();}return new FreeSqlBuilder().UseConnectionString(DataType.Sqlite, builder.Configuration.GetConnectionString("DefaultConnection")).UseMonitorCommand(cmd => Console.WriteLine($"Sql:{cmd.CommandText}")) //监听SQL语句.UseAutoSyncStructure(true) //自动同步实体结构到数据库,FreeSql不会扫描程序集,只有CRUD时才会生成表。.Build();
});// 使用内存加载配置 
builder.Services.AddReverseProxy().LoadFromMemory(GatewayService.Routes, GatewayService.Clusters);var app = builder.Build();app.UseCors("AllowAll");app.UseMiddleware<RequestLogMiddleware>();
app.UseMiddleware<StaticFileProxyMiddleware>();// 配置MiniApis服务
app.MapRequestLog();
app.MapStaticFileProxy();
app.MapFileStorage();
app.MapGateway();
app.MapAuthority();
app.MapCertificate();
app.MapSetting();app.UseAuthentication();
app.UseAuthorization();app.MapReverseProxy();await app.RunAsync();

上面是完整的代码,我们不过多讲解,只讲解HTTP3需要哪些配置

首先,我们的Gateway支持动态加载证书,而HTTP3是强制使用证书的,我们在这里提供了动态配置HTTP3的实现。

builder.WebHost.UseKestrel(options =>
{// 配置多个域名证书options.ConfigureHttpsDefaults(adapterOptions =>{adapterOptions.ServerCertificateSelector = (_, name) =>{// 从Certificate服务中获取if (string.IsNullOrEmpty(name) ||!CertificateService.CertificateEntityDict.TryGetValue(name, out var certificate)) return new X509Certificate2();var path = Path.Combine("/data/", certificate.Path);if (File.Exists(path)) return new X509Certificate2(path, certificate.Password);Console.ForegroundColor = ConsoleColor.Red;Console.WriteLine($"证书文件不存在:{path}");Console.ResetColor();throw new Exception($"证书文件不存在:{path}");};});
});

上面配置好了证书,下面我们配置启用HTTP3,下面我们对于容器会监听俩个端口8080,8081,8080是Http端口,所以不需要开启HTTP3,我们在监听8081的时候修改了协议为HttpProtocols.Http1AndHttp2AndHttp3,然后portOptions.UseHttps()强制使用HTTPS,Http1AndHttp2AndHttp3是自动支持多个协议,如果HTTP3不支持则会降级支持HTTP2如果HTTP2不支持则降级支持HTTP1,由于浏览器不确定你是否支持HTTP3所以会先请求一个HTTP2或HTTP1协议的请求,如果支持的话框架会自动给响应头返回一个Alt-Svc的值。

builder.WebHost.ConfigureKestrel(kestrel =>
{kestrel.Limits.MaxRequestBodySize = null;kestrel.ListenAnyIP(8081, portOptions =>{portOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;portOptions.UseHttps();});kestrel.ListenAnyIP(8080, portOptions =>{portOptions.Protocols = HttpProtocols.Http1AndHttp2;});
});

上面俩个配置完成以后我们修改我们的Dockerfile,由于微软提供的默认的镜像是不提供libmsquic,所以我们需要自己写一个Dockerfile,打开我们Gateway项目中的Dockerfile,并且添加libmsquic的构建流程

FROM mcr.microsoft.com/dotnet/aspnet:8.0.1-bookworm-slim-amd64 AS base
USER root
RUN  apt update \&& apt-get install -y --no-install-recommends curl \&& curl -sSL -O https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb \&& dpkg -i packages-microsoft-prod.deb \&& rm packages-microsoft-prod.deb \&& apt-get update \&& apt-get install -y libmsquic \&& apt-get purge -y --auto-remove wget && apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /app
EXPOSE 8080
EXPOSE 8081FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["src/Gateway/Gateway.csproj", "src/Gateway/"]
RUN dotnet restore "./src/Gateway/Gateway.csproj"
COPY . .
WORKDIR "/src/src/Gateway"
RUN dotnet build "./Gateway.csproj" -c $BUILD_CONFIGURATION -o /app/buildFROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Gateway.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=falseFROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Gateway.dll"]

在构建镜像的时候需要使用root权限,否则可能导致权限不足构建失败,上面完成了我们本地的镜像构建和.NET Core的HTTP3的启用,然后需要我们构建好了镜像就可以在服务器中跑一个容器了,在运行容器的时候还会有一个坑,下面我们来慢慢讲解,

部署服务

打开我们的服务器使用Linux服务器打开,下面是我们的Gateway的一个Compose版本,由于Docker端口监听默认使用的是tcp,所以我们需要监听俩个协议,因为HTTP3是基于UDP实现的,这也是坑之一,还有如果登录失败可能是映射目录权限不够创建Sqlite文件失败导致。

services:gateway-api:image: registry.token-ai.cn:8300/gatewayrestart: alwaysenvironment:USER: rootPASS: Aa010426.ports:- 8080:8080- 8081:8081/udp- 8081:8081/tcpvolumes:- ./data:/data/gateway-web:image: registry.cn-shenzhen.aliyuncs.com/tokengo/gateway-webrestart: alwaysprivileged: trueenvironment:api_url: http://这里是你上面的Gateway-api能在浏览器本地请求的地址:8200/ports:- 1000:80

然后指向我们的sudo docker-compose up -d

指向完成以后我们打开我们的gateway-web的界面,并且登录进去,如果你没有设置环境变量的话默认密码是rootAa010426.

打开我们的代理设置,添加一个集群:

打开路由,点击添加路由,

打开证书管理,点击添加证书:

将我们的证书上传以后点击右上角的刷新缓存,则会生效,还需要注意将我们的域名解析到服务器当中。上面我们用的是gitea.token-ai.cn,注意的是自签证书似乎不能使用。上面操作完成以后点击我们右上角的刷新缓存,然后访问我们的https://gitea.token-ai.cn:8081,然后打开浏览器的F12,我们可以看到我们的,我们的协议除了第一个都是h3协议,这是因为第一个请求是不确定你是否支持h3所以发起一个h1或h2的协议然后,如果你的响应头响应了Alt-Svc则会下次请求使用h3,

还需要注意的是,Alt-Svc:h3=":8081"; ma=86400的8081是前端访问的端口,这个是需要和访问端口一致,如果不一致也不会使用h3。

注意事项

某些浏览器不一定支持所以需要先确认浏览器是否开启QUIC

还需要确认服务器防火墙是否开启UDP

然后根据上面的文档一步一步来即可,或者可以加群询问群主。

结尾

来着token的分享

开源地址:https://gitee.com/hejiale010426/Gateway
github: https://github.com/239573049/Gateway
技术交流群:737776595

这篇关于如何让你的.NET WebAPI程序支持HTTP3?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/640664

相关文章

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

如何用java对接微信小程序下单后的发货接口

《如何用java对接微信小程序下单后的发货接口》:本文主要介绍在微信小程序后台实现发货通知的步骤,包括获取Access_token、使用RestTemplate调用发货接口、处理AccessTok... 目录配置参数 调用代码获取Access_token调用发货的接口类注意点总结配置参数 首先需要获取Ac

讯飞webapi语音识别接口调用示例代码(python)

《讯飞webapi语音识别接口调用示例代码(python)》:本文主要介绍如何使用Python3调用讯飞WebAPI语音识别接口,重点解决了在处理语音识别结果时判断是否为最后一帧的问题,通过运行代... 目录前言一、环境二、引入库三、代码实例四、运行结果五、总结前言基于python3 讯飞webAPI语音

一文教你解决Python不支持中文路径的问题

《一文教你解决Python不支持中文路径的问题》Python是一种广泛使用的高级编程语言,然而在处理包含中文字符的文件路径时,Python有时会表现出一些不友好的行为,下面小编就来为大家介绍一下具体的... 目录问题背景解决方案1. 设置正确的文件编码2. 使用pathlib模块3. 转换路径为Unicod

基于Python开发PDF转Doc格式小程序

《基于Python开发PDF转Doc格式小程序》这篇文章主要为大家详细介绍了如何基于Python开发PDF转Doc格式小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用python实现PDF转Doc格式小程序以下是一个使用Python实现PDF转DOC格式的GUI程序,采用T

基于.NET编写工具类解决JSON乱码问题

《基于.NET编写工具类解决JSON乱码问题》在开发过程中,我们经常会遇到JSON数据处理的问题,尤其是在数据传输和解析过程中,很容易出现编码错误导致的乱码问题,下面我们就来编写一个.NET工具类来解... 目录问题背景核心原理工具类实现使用示例总结在开发过程中,我们经常会遇到jsON数据处理的问题,尤其是

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服

将java程序打包成可执行文件的实现方式

《将java程序打包成可执行文件的实现方式》本文介绍了将Java程序打包成可执行文件的三种方法:手动打包(将编译后的代码及JRE运行环境一起打包),使用第三方打包工具(如Launch4j)和JDK自带... 目录1.问题提出2.如何将Java程序打包成可执行文件2.1将编译后的代码及jre运行环境一起打包2

定价129元!支持双频 Wi-Fi 5的华为AX1路由器发布

《定价129元!支持双频Wi-Fi5的华为AX1路由器发布》华为上周推出了其最新的入门级Wi-Fi5路由器——华为路由AX1,建议零售价129元,这款路由器配置如何?详细请看下文介... 华为 Wi-Fi 5 路由 AX1 已正式开售,新品支持双频 1200 兆、配有四个千兆网口、提供可视化智能诊断功能,建

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创