如何让你的.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[]>());
#endregion
var 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 Jwt
builder.Services
.AddAuthorization()
.AddJwtBearerAuthentication();
#endregion
builder.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 MB
x.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 8081
FROM 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/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Gateway.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM 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/gateway
restart: always
environment:
USER: root
PASS: Aa010426.
ports:
- 8080:8080
- 8081:8081/udp
- 8081:8081/tcp
volumes:
- ./data:/data/
gateway-web:
image: registry.cn-shenzhen.aliyuncs.com/tokengo/gateway-web
restart: always
privileged: true
environment:
api_url: http://这里是你上面的Gateway-api能在浏览器本地请求的地址:8200/
ports:
- 1000:80
然后指向我们的sudo docker-compose up -d
指向完成以后我们打开我们的gateway-web的界面,并且登录进去,如果你没有设置环境变量的话默认密码是root:Aa010426.
打开我们的代理设置,添加一个集群:


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

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

将我们的证书上传以后点击右上角的刷新缓存,则会生效,还需要注意将我们的域名解析到服务器当中。上面我们用的是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?的更多相关文章
- WinServer2008R2 + IIS 7.5 + .NET4.0 经典模式 运行WebAPI程序报404错误的解决方案
在Windows Server 2008 R2系统下,IIS 7.5 + .NET Framework 4.0的运行环境,以经典模式(Classic Mode)部署一个用.NET 4.0编译的 Web ...
- ASP.NET MVC]WebAPI应用支持HTTPS的经验总结
WebAPI应用支持HTTPS的经验总结 在我前面介绍的WebAPI文章里面,介绍了WebAPI的架构设计方面的内容,其中提出了现在流行的WebAPI优先的路线,这种也是我们开发多应用(APP.微信. ...
- 你的程序支持复杂的时间调度嘛?如约而来的 java 版本
你的程序支持复杂的时间调度嘛? 这篇文章介绍了时间适配器的c#版本,是给客户端用的,服务器自然也要有一套对应的做法,java版本的 [年][月][日][星期][时间] [*][*][*][*][*] ...
- SpiderMonkey-让你的C++程序支持JavaScript脚本
译序 有些网友对为什么D2JSP能执行JavaScript脚本程序感到奇怪,因此我翻译了这篇文章,原文在这里.这篇教程手把手教你怎样利用SpiderMonkey创建一个能执行JavaScript脚本的 ...
- 如何让你的Python程序支持多语言
如何让你的Python程序支持多语言 本文介绍如何通过Python标准库gettext帮助你的程序支持多语言. 代码例子 import random guessesTaken = 0 print(_( ...
- WPF应用程序支持多国语言解决方案
原文:WPF应用程序支持多国语言解决方案 促使程序赢得更多客户的最好.最经济的方法是使之支持多国语言,而不是将潜在的客户群限制为全球近70亿人口中的一小部分.本文介绍四种实现WPF应用程序支持多国语言 ...
- 让.Net程序支持命令行启动
很多时候,我们需要让程序支持命令行启动,这个时候则需要一个命令行解析器,由于.Net BCL并没有内置命令行解析库,因此需要我们自己实现一个.对于简单的参数来说,自己写一个字符串比较函数来分析args ...
- TMS WEB Core v1.2预览版:新的Electron应用程序支持
2019年2月20日,星期三 几个月前,我们已经开始与Electron进行实验.在工作概念验证之后,我们的目标是为Delphi开发人员尽可能多地包装Electron API.但当然不仅仅是可以使用的E ...
- 小程序支持打开APP了 还有小程序的标题栏也可以自定义
就在刚刚,小程序上线两个新能力——小程序支持打开APP了,小程序的标题栏区域开放自定义.用户可以在小程序里更方便地获取到APP的服务了——APP链接分享到微信,打开小程序页面后,用户从该小程序页面里, ...
- 小程序支持打开APP
根据微信的官方文档,小程序支持打开APP,专门研究了下这个API有什么,官方文档地址如下 https://mp.weixin.qq.com/debug/wxadoc/dev/component/but ...
随机推荐
- LLaMA大型语言模型
LLaMA (Large Language Model Meta AI)是Meta公司发布的大型语言模型系列,近日LLaMA种子文件被合并到了GitHub 上,同时一些项目维护者给予了批准,目前该项目 ...
- 善用 vscode 的批量和模板技巧来提效
vs code 其实有很多实用的技巧可以在日常工作中带来很大的提效,但可能是开发中没有相应的痛点场景,因此有些技巧接触的人不多 本篇就来介绍下多光标的批量操作和模板代码两种技巧在日常工作中的提效 涉及 ...
- 掌握语义内核(Semantic Kernel):如何精进你的提示词工程
在人工智能的海洋里,大型语言模型(LLM AI)是高速发展的一艘巨轮,而有效地与其沟通和指导其行为的锚,正是提示语(prompts).提示语是我们提供给模型的输入或查询,以期获取特定的响应.当今,提示 ...
- puppeteer的简单使用
引言 对于编写应用程序,尤其是要部署上线投入生产使用的应用,QA是其中重要的一环,在过去的工作经历中,我参与的项目开发,大多是由测试同学主要来把控质量的,我很少编写前端方面的测试代码,对于测试工具的使 ...
- 面试官:禁用Cookie后Session还能用吗?
Cookie 和 Session 是 Web 应用程序中用于保持用户状态的两种常见机制,它们之间既有联系也有区别. Cookie 是由服务器在 HTTP 响应中发送给客户端(通常是浏览器)的一小段数据 ...
- 9、线性布局(Row和Column)
自定义的IconContainer void main() { runApp(MaterialApp( theme: ThemeData(primarySwatch: Colors.yellow), ...
- 高效联调,可靠发布!华为云推出CodeArts Release发布管理服务
摘要:华为云全新推出CodeArts Release发布管理服务,旨在将华为多年形成的发布实践外溢,帮助企业提升软件发布质量和效率,降低生产环境的发布风险. 本文分享自华为云社区<高效联调,可靠 ...
- 跟我学ModelArts丨探索ModelArts平台个性化联邦学习API
摘要:ModelArts提供了一个实现个性化联邦学习的API--pytorch_fedamp_emnist_classification,它主要是让拥有相似数据分布的客户进行更多合作的一个横向联邦学习 ...
- 案例解读华为隐私计算产品TICS如何实现城市跨部门数据隐私计算
摘要:本文介绍华为可信智能计算服务TICs是如何助力城市跨部门数据实现隐私计算的. 本文分享自华为云社区<基于华为隐私计算产品TICS实现城市跨部门数据隐私计算,助力实现普惠金融>,作者: ...
- KubeEdge边缘计算在顺丰科技工业物联网中的实践
摘要:顺丰物联网平台负责人胡典钢为大家带来了 " 边缘计算在工业物联网中的应用实践与思考 " ,阐述了工业物联网的发展背景.整体架构设计以及边缘计算在此过程中承担的重要角色,并梳理 ...