Kestrel 完整笔记
目录
1. Kestrel 是什么
1.1 官方定义
Kestrel = ASP.NET Core 内置的跨平台 Web 服务器
1.2 通俗理解
Kestrel = 监听服务 + 构建服务
Kestrel 的双重职责:
1. 监听服务(Listening Service)
- 在网络端口上监听
- 等待和接收 HTTP 请求
- 这是"守门员"的角色
2. 构建服务(Building Service)
- 构建整个系统的 HTTP 服务能力
- 提供 HTTP 协议处理
- 搭建请求-响应的基础设施
- 这是"建筑工人"的角色
Kestrel = 你的程序的 HTTP 服务引擎
它是一个软件组件,负责:
- 在网络端口上等待 HTTP 请求
- 接收请求
- 解析 HTTP 协议
- 将请求传递给你的代码
- 将你的代码返回的结果包装成 HTTP 响应
- 发送响应给客户端
- 深入解析 .NET 8 Kestrel:高性能 Web 服务器的架构与最佳实践Kestrel 是 .NET 8 中用于处 - 掘金
- ASP.NET Core 中的 Kestrel Web 服务器 | Microsoft Learn
1.3 形象比喻
你的 ASP.NET Core 程序 = 一家餐厅
Kestrel = 餐厅的前台接待员
├─ 在门口等待客人(监听端口)
├─ 接待客人进门(接收请求)
├─ 理解客人需求(解析HTTP)
├─ 转告厨房(传给你的代码)
├─ 接收厨房做好的菜(接收响应)
└─ 送给客人(发送响应)
你的业务代码 = 厨房(处理业务逻辑)
1.4 技术架构中的位置
客户端(浏览器/APP)
↓ HTTP 请求
[Kestrel] ← 这是网络边界
↓
[ASP.NET Core 请求管道]
├─ 路由
├─ 认证
├─ 授权
└─ 中间件
↓
[你的控制器/代码]
↓ 返回结果
[ASP.NET Core 管道处理]
↓
[Kestrel]
↓ HTTP 响应
客户端
1.5 代码中的 Kestrel
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run(); // ← 这行代码启动 Kestrel
当执行 app.Run() 时:
1. 托管系统启动
2. Kestrel 被初始化
3. Kestrel 绑定到指定的网络端口
4. Kestrel 开始"监听"
5. 控制台输出:Now listening on: http://localhost:5000
6. 程序进入等待状态,不会退出
7. 每当有 HTTP 请求到来,Kestrel 接收并处理
2. 为什么叫"监听"
2.1 "监听"的含义
监听(Listen)= 在网络端口上等待连接
这是网络编程的标准术语。
2.2 底层原理
// Kestrel 底层做的事情(简化版)
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 绑定到端口
socket.Bind(new IPEndPoint(IPAddress.Any, 5000));
// 开始监听(Listen)
socket.Listen(100); // ← 这就是"监听"
// 等待客户端连接
while (true)
{
Socket client = socket.Accept(); // 阻塞等待
// 处理客户端请求...
}
网络通信的基本原理:
客户端(浏览器) 服务器(你的程序)
| |
| 1. 我要连接 192.168.1.100:5000 |
|--------------------------------→ |
| | 2. 检查:有程序在监听 5000 端口吗?
| | - 有 → 接受连接
| | - 没有 → 拒绝连接
| 3. ←---------------------------- |
| 连接建立 |
如果没有监听:
客户端连接 → 服务器 5000 端口 → 没有程序监听 → 连接失败
浏览器显示:ERR_CONNECTION_REFUSED(连接被拒绝)
2.3 "监听"的三个步骤
1. Bind(绑定)
- Kestrel 告诉操作系统:"我要用 5000 端口"
- 操作系统分配端口给 Kestrel
2. Listen(监听)
- Kestrel 告诉操作系统:"开始接收这个端口的连接"
- 操作系统将到达该端口的请求放入队列
3. Accept(接受)
- Kestrel 从队列中取出连接
- 开始处理 HTTP 请求
2.4 为什必须"监听"
网络通信的基本规则:
客户端要连接服务器,必须知道:
1. 服务器的 IP 地址
2. 服务器的端口号
服务器要接受连接,必须:
1. 在指定端口上"监听"
2. 等待客户端连接
示例:
用户在浏览器输入:http://192.168.1.100:5000/api/users
浏览器做的事:
1. 解析域名/IP:192.168.1.100
2. 解析端口:5000
3. 向 192.168.1.100 的 5000 端口发起 TCP 连接
服务器端(Kestrel):
1. 必须已经在 5000 端口上"监听"
2. 才能接收到这个连接
3. 如果没有监听 5000 端口 → 连接失败
2.5 查看监听状态
Windows:
netstat -ano | findstr :5000
# 输出:TCP 0.0.0.0:5000 0.0.0.0:0 LISTENING 12345
# ↑ ↑
# 监听端口 监听状态
Linux:
netstat -tuln | grep :5000
# 或
ss -tuln | grep :5000
2.6 监听范围
// 只监听本机回环接口
builder.WebHost.UseUrls("http://localhost:5000");
// 或
builder.WebHost.UseUrls("http://127.0.0.1:5000");
// 结果:只有本机可以访问
// 监听所有网络接口
builder.WebHost.UseUrls("http://*:5000");
// 或
builder.WebHost.UseUrls("http://0.0.0.0:5000");
// 结果:任何能到达服务器的客户端都可以访问
// 监听指定网络接口
builder.WebHost.UseUrls("http://192.168.1.100:5000");
// 结果:只能通过这个 IP 访问
3. Kestrel 的真实工作
3.1 核心职责
Kestrel = 系统的 HTTP 服务处理引擎
Kestrel 的工作内容:
1. 网络层
├─ 绑定端口
├─ 监听连接
├─ 接受 TCP 连接
└─ 管理连接池
2. HTTP 协议层
├─ 解析 HTTP 请求(请求行、请求头、请求体)
├─ 支持 HTTP/1.1
├─ 支持 HTTP/2
├─ 支持 HTTP/3(QUIC)
└─ 组装 HTTP 响应
3. 数据流转
├─ 将 HTTP 请求转换为 HttpContext
├─ 传递给 ASP.NET Core 管道
├─ 接收管道返回的响应
└─ 发送给客户端
4. 连接管理
├─ Keep-Alive 连接复用
├─ 超时处理
├─ 连接限制
└─ 优雅关闭
3.2 请求处理全流程
客户端发送:GET /api/users HTTP/1.1
[Kestrel 接收]
↓
1. 接收 TCP 数据流
2. 解析 HTTP 协议
- 请求方法:GET
- 路径:/api/users
- 协议版本:HTTP/1.1
- 请求头:Host, User-Agent, Accept...
3. 创建 HttpContext 对象
- HttpContext.Request.Method = "GET"
- HttpContext.Request.Path = "/api/users"
- HttpContext.Request.Headers = [...]
↓
[传递给 ASP.NET Core 管道]
↓
[路由中间件] → 匹配到控制器
[认证中间件] → 验证身份
[授权中间件] → 检查权限
[控制器执行] → 返回数据
↓
[管道返回响应]
↓
[Kestrel 接收响应]
↓
4. 组装 HTTP 响应
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123
{"users": [...]}
5. 发送 TCP 数据流
↓
客户端接收响应
3.3 代码验证
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 所有请求都经过 Kestrel
app.MapGet("/api/users", () =>
{
return new[] { "User1", "User2" };
});
app.MapPost("/api/users", (User user) =>
{
// Kestrel 已经将请求体反序列化为 User 对象
return Results.Created($"/api/users/{user.Id}", user);
});
app.Run();
// Kestrel 启动,监听端口
// 所有 /api/users 的请求都由 Kestrel 接收和处理
3.4Kestrel 构建的完整 HTTP 服务
从网络字节到你的代码:
1. 客户端发送原始字节流
↓
47 45 54 20 2f 61 70 69 2f 75 73 65 72 73 20 48 54 54 50 ...
(这是 "GET /api/users HTTP/1.1..." 的二进制)
↓
2. Kestrel 接收字节流
↓
3. Kestrel 解析为 HTTP 请求
┌─────────────────────────┐
│ Method: GET │
│ Path: /api/users │
│ Protocol: HTTP/1.1 │
│ Headers: │
│ Host: localhost:5000 │
│ User-Agent: Chrome │
│ Accept: application/json │
└─────────────────────────┘
↓
4. Kestrel 构建 HttpContext 对象
HttpContext {
Request: {
Method: "GET",
Path: "/api/users",
Headers: {...}
},
Response: {
StatusCode: 200,
Headers: {...},
Body: ...
}
}
↓
5. 传递给 ASP.NET Core 管道
↓
6. 你的代码处理
app.MapGet("/api/users", () => new[] { "User1", "User2" });
↓
7. 返回结果给 Kestrel
return new[] { "User1", "User2" };
↓
8. Kestrel 组装 HTTP 响应
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 28
["User1","User2"]
↓
9. Kestrel 转换为字节流
48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b ...
↓
10. 发送给客户端
你的代码只需要:
app.MapGet("/api/users", () => new[] { "User1", "User2" });
Kestrel 帮你做了所有底层工作!
3.5 Kestrel 构建的 HTTP 能力
HTTP/1.1 支持
// Kestrel 自动支持
// - Keep-Alive 连接复用
// - 分块传输编码
// - 管道化请求
HTTP/2 支持
builder.WebHost.ConfigureKestrel(options =>
{
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
listenOptions.UseHttps();
listenOptions.Protocols = HttpProtocols.Http2;
});
});
// 支持:
// - 多路复用
// - 服务器推送
// - 头部压缩
HTTP/3 支持 (QUIC)
builder.WebHost.ConfigureKestrel(options =>
{
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
listenOptions.UseHttps();
listenOptions.Protocols = HttpProtocols.Http3;
});
});
WebSocket 支持
app.UseWebSockets();
app.Map("/ws", async context =>
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
// Kestrel 处理 WebSocket 协议升级
}
});
HTTPS/TLS 支持
builder.WebHost.ConfigureKestrel(options =>
{
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
listenOptions.UseHttps("cert.pfx", "password");
// Kestrel 处理 TLS 握手和加密
});
});
3.6 Kestrel 不做什么
❌ 路由匹配(由路由中间件做)
❌ 身份验证(由认证中间件做)
❌ 授权检查(由授权中间件做)
❌ 业务逻辑(由你的代码做)
❌ 数据库操作(由你的代码做)
❌ 静态文件服务(由静态文件中间件做)
✅ Kestrel 只负责 HTTP 协议层的事情
有了 Kestrel,你的程序:
- ✅ 成为一个 Web 服务器
- ✅ 可以处理 HTTP/HTTPS 请求
- ✅ 支持 HTTP/1.1, HTTP/2, HTTP/3
- ✅ 可以对外提供 API/网站服务
4. 系统主地址概念
4.1 什么是"系统主地址"
系统主地址 = Kestrel 监听的地址 = 整个应用的网络入口
builder.WebHost.UseUrls("http://localhost:5000");
// ↑
// 这就是系统主地址
4.2 为什么叫"主地址"
因为所有功能都基于这个地址:
Kestrel 监听:http://localhost:5000
↓
所有请求都通过这个地址进入:
- API 接口: http://localhost:5000/api/users
- Swagger UI: http://localhost:5000/swagger
- 健康检查: http://localhost:5000/health
- 静态文件: http://localhost:5000/images/logo.png
- SignalR Hub: http://localhost:5000/chatHub
这是唯一的入口! 就像一栋楼只有一个大门。
4.3 配置主地址的方式
方式1:UseUrls(代码)
var builder = WebApplication.CreateBuilder(args);
// 配置主地址
builder.WebHost.UseUrls("http://localhost:8000");
var app = builder.Build();
app.Run();
// Kestrel 监听:http://localhost:8000
// 系统主地址:http://localhost:8000
方式2:appsettings.json
{
"Urls": "http://localhost:8000"
}
var builder = WebApplication.CreateBuilder(args);
// ASP Net Core默认 appsettings.json 中的 "Urls"关键字
var app = builder.Build();
app.Run();
方式3:环境变量
export ASPNETCORE_URLS="http://localhost:8000"
dotnet MyApp.dll
方式4:命令行
dotnet MyApp.dll --urls "http://localhost:8000"
4.4 主地址的范围
// 只监听本地(开发环境)
"http://localhost:5000"
// 只有本机可以访问 http://localhost:5000
// 监听所有网卡(生产环境)
"http://*:5000"
// 可以通过服务器任何IP访问:
// - http://localhost:5000
// - http://192.168.1.100:5000
// - http://服务器公网IP:5000
// 监听指定IP
"http://192.168.1.100:5000"
// 只能通过这个IP访问
4.5 多个主地址
// 同时监听 HTTP 和 HTTPS
builder.WebHost.UseUrls(
"http://localhost:5000", // HTTP
"https://localhost:5001" // HTTPS
);
// 系统有两个主地址:
// - http://localhost:5000
// - https://localhost:5001
5. 编辑工具的地址
5.1 什么是"编辑工具的地址"
编辑工具 = IDE(Visual Studio / Rider / VS Code)
编辑工具的地址 = launchSettings.json 中配置的地址
5.2 launchSettings.json
位置: Properties/launchSettings.json
{
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5000;https://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
5.3 工作原理
当你在 IDE 中按 F5 启动时:
1. IDE 读取 launchSettings.json
2. 找到选中的 profile(如 "https")
3. 读取 applicationUrl
4. IDE 执行命令:
dotnet run --urls "http://localhost:5000;https://localhost:5001"
5. 命令行参数传递给程序
6. WebHost 接收参数
7. Kestrel 监听这些地址
5.4 launchSettings.json 的特点
✅ 只在 IDE 中运行时生效
✅ 方便开发调试
✅ 可以配置多个 profile(如 http, https, Docker)
❌ 发布后不存在这个文件
❌ 直接运行 dotnet MyApp.dll 时不读取
❌ 部署到服务器时不生效
5.5 验证
测试1:IDE 运行
按 F5 启动
→ 使用 launchSettings.json 的地址
→ 监听 http://localhost:5000
测试2:命令行运行
dotnet run
→ 也会读取 launchSettings.json(如果存在)
→ 监听 http://localhost:5000
测试3:发布后运行
dotnet publish -c Release
cd bin/Release/net8.0/publish
dotnet MyApp.dll
→ launchSettings.json 不存在
→ 使用默认地址 http://localhost:5000
5.6 编辑工具地址 vs 主地址
| 概念 | 配置位置 | 作用范围 | 优先级 |
|---|---|---|---|
| 编辑工具地址 | launchSettings.json | IDE 开发时 | 低 |
| 系统主地址 | UseUrls/Urls/环境变量 | 所有环境 | 高 |
如果同时配置:
// launchSettings.json
"applicationUrl": "http://localhost:5000"
// Program.cs
builder.WebHost.UseUrls("http://localhost:8000");
结果:Kestrel 监听 8000(UseUrls 优先级更高)
6. 不同部署场景的地址配置
| 场景 | Kestrel 监听地址 | 外部访问地址 | Kestrel 角色 |
|---|---|---|---|
| 本地开发(IDE) | localhost:5000 | localhost:5000 | 监听 + 构建 |
| 本地开发(局域网) | *:5000 | 192.168.x.x:5000 | 监听 + 构建 |
| Linux 直接部署 | *:80 | 服务器IP:80 | 监听 + 构建 |
| Nginx 反向代理 | localhost:5000 | 域名:443 | 监听 + 构建 |
| IIS In-Process | 不适用 | IIS地址 | ❌ 不使用 |
| IIS Out-of-Process | 随机端口 | IIS地址 | 监听 + 构建 |
| Docker | 0.0.0.0:80 | 容器映射端口 | 监听 + 构建 |
| Kubernetes | 0.0.0.0:80 | Service地址 | 监听 + 构建 |
6.1 场景1:本地开发(IDE)
目标: 只有开发者自己访问
配置:
// launchSettings.json
{
"profiles": {
"Development": {
"applicationUrl": "http://localhost:5000"
}
}
}
特点:
- 只监听 localhost
- 外部无法访问
- 安全
访问:
开发者访问:http://localhost:5000 ✅
同事访问: http://你的电脑IP:5000 ❌ 无法访问
6.2 场景2:本地开发(允许局域网访问)
目标: 让同事/测试人员访问
配置:
var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsDevelopment())
{
// 监听所有网卡
builder.WebHost.UseUrls("http://*:5000");
}
var app = builder.Build();
app.Run();
访问:
你自己: http://localhost:5000 ✅
同事: http://192.168.1.100:5000 ✅
外网用: ❌ 无法访问(局域网内)
6.3 场景3:Linux 服务器直接部署
目标: 程序直接暴露在公网
配置:
// appsettings.Production.json
{
"Urls": "http://*:80"
}
# 部署
dotnet MyApp.dll
# Kestrel 监听 80 端口
架构:
用户浏览器
↓
http://47.103.25.88:80
↓
Kestrel 监听 0.0.0.0:80
↓
你的程序
问题:
- ❌ 没有 HTTPS(不安全)
- ❌ 端口直接暴露
- ❌ 无法负载均衡
6.4 场景4:Nginx 反向代理(推荐)
目标: 生产环境标准部署
架构:
用户浏览器
↓
https://myapp.com (443端口)
↓
Nginx (处理 HTTPS, 负载均衡)
↓
http://localhost:5000 (内网)
↓
Kestrel 监听 localhost:5000
↓
你的程序
Nginx 配置: /etc/nginx/sites-available/myapp
server {
listen 80;
server_name myapp.com;
# HTTP 重定向到 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name myapp.com;
# SSL 证书
ssl_certificate /etc/ssl/certs/myapp.crt;
ssl_certificate_key /etc/ssl/private/myapp.key;
location / {
# 转发到 Kestrel
proxy_pass http://localhost:5000;
# 传递真实客户端信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Kestrel 配置:
// appsettings.Production.json
{
"Urls": "http://localhost:5000"
}
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 配置转发头(重要!)
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
});
var app = builder.Build();
// 使用转发头中间件
app.UseForwardedHeaders();
app.Run();
地址对应关系:
| 层级 | 监听地址 | 说明 |
|---|---|---|
| 用户访问 | https://myapp.com | 域名 + HTTPS |
| Nginx 监听 | 0.0.0.0:443 | 监听所有IP的443端口 |
| Nginx 转发 | http://localhost:5000 | 转发到本机5000端口 |
| Kestrel 监听 | http://localhost:5000 | 只监听本机5000端口 |
必须匹配: Nginx 转发地址 = Kestrel 监听地址
6.5 场景5:IIS 托管(Windows)
模式A:In-Process(进程内)
架构:
用户请求
↓
IIS (80/443端口)
↓
你的程序(运行在IIS进程内)
↓
不使用 Kestrel ❌
web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*"
modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet"
arguments=".\MyApp.dll"
stdoutLogEnabled="false"
hostingModel="inprocess">
<!-- ↑ In-Process 模式 -->
</aspNetCore>
</system.webServer>
</configuration>
Program.cs:
var builder = WebApplication.CreateBuilder(args);
// UseUrls 会被忽略
// builder.WebHost.UseUrls("..."); // ← 无效
var app = builder.Build();
app.Run();
特点:
- ❌ Kestrel 不工作
- ✅ IIS 直接处理 HTTP
- ✅ 性能最好
- ❌ 只能 Windows
模式B:Out-of-Process(进程外)
架构:
用户请求
↓
IIS (80/443端口)
↓
转发到 http://localhost:随机端口
↓
Kestrel 监听(独立进程)
↓
你的程序
web.config:
<aspNetCore processPath="dotnet"
arguments=".\MyApp.dll"
hostingModel="outofprocess">
<!-- ↑ Out-of-Process 模式 -->
</aspNetCore>
Program.cs:
var builder = WebApplication.CreateBuilder(args);
// IIS 会自动设置端口,不需要手动配置
// builder.WebHost.UseUrls("..."); // 可选
var app = builder.Build();
app.Run();
特点:
- ✅ 使用 Kestrel
- ✅ IIS 转发请求
- ✅ 程序独立进程
6.6 场景6:Docker 容器
Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY publish/ .
# 设置环境变量
ENV ASPNETCORE_URLS=http://+:80
EXPOSE 80
ENTRYPOINT ["dotnet", "MyApp.dll"]
或在 Program.cs 配置:
var builder = WebApplication.CreateBuilder(args);
// Docker 中必须监听 0.0.0.0
builder.WebHost.UseUrls("http://0.0.0.0:80");
var app = builder.Build();
app.Run();
运行:
docker build -t myapp .
docker run -d -p 8080:80 myapp
# 容器内:Kestrel 监听 0.0.0.0:80
# 宿主机:映射到 8080 端口
# 访问:http://localhost:8080
6.7 场景7:Kubernetes
Deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
template:
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 80
env:
- name: ASPNETCORE_URLS
value: "http://+:80"
---
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
app: myapp
架构:
用户请求
↓
LoadBalancer (公网IP)
↓
Service (ClusterIP)
↓
Pod 1: Kestrel 监听 0.0.0.0:80
Pod 2: Kestrel 监听 0.0.0.0:80
Pod 3: Kestrel 监听 0.0.0.0:80
7. 完整配置示例
7.1 开发环境配置
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// 开发环境配置
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
// 开发时不需要配置 UseUrls
// 使用 launchSettings.json 的配置即可
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
launchSettings.json:
JSON
{
"profiles": {
"https": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:5000;https://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
7.2 生产环境配置(Nginx)
appsettings.Production.json:
JSON
{
"Urls": "http://localhost:5000",
"Logging": {
"LogLevel": {
"Default": "Warning"
}
}
}
Program.cs:
C#
var builder = WebApplication.CreateBuilder(args);
// 配置服务
builder.Services.AddControllers();
// 配置转发头(Nginx 反向代理必需)
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
var app = builder.Build();
// 使用转发头
app.UseForwardedHeaders();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Nginx 配置:
Nginx
server {
listen 443 ssl;
server_name myapp.com;
ssl_certificate /etc/ssl/certs/myapp.crt;
ssl_certificate_key /etc/ssl/private/myapp.key;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
7.3 根据环境自动配置
C#
var builder = WebApplication.CreateBuilder(args);
// 根据环境配置监听地址
if (builder.Environment.IsDevelopment())
{
// 开发:使用 launchSettings.json
}
else if (builder.Environment.IsProduction())
{
// 生产:从配置文件读取
// 或明确指定
builder.WebHost.UseUrls("http://localhost:5000");
}
var app = builder.Build();
app.Run();
7.4 详细的 Kestrel 配置
C#
builder.WebHost.ConfigureKestrel(options =>
{
// 监听配置
options.Listen(IPAddress.Loopback, 5000); // HTTP
options.Listen(IPAddress.Loopback, 5001, listenOptions =>
{
listenOptions.UseHttps("cert.pfx", "password"); // HTTPS
});
// 性能限制
options.Limits.MaxConcurrentConnections = 100;
options.Limits.MaxConcurrentUpgradedConnections = 100;
options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10MB
options.Limits.MinRequestBodyDataRate = new MinDataRate(
bytesPerSecond: 100,
gracePeriod: TimeSpan.FromSeconds(10)
);
// 超时设置
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30);
});
总结
Kestrel 核心要点
-
Kestrel 是什么
- ASP.NET Core 内置的 HTTP 服务器
- 负责处理所有 HTTP 请求和响应
-
为什么叫监听
- 在网络端口上等待连接
- 网络编程的标准术语
-
系统主地址
- Kestrel 监听的地址
- 整个应用的网络入口
- 所有功能都基于这个地址
-
编辑工具地址
- launchSettings.json 中的配置
- 只在 IDE 开发时生效
- 优先级低于代码配置
-
部署场景
- 开发:localhost,安全隔离
- 直接部署:0.0.0.0,监听所有IP
- 反向代理:localhost,内网监听
- IIS:In-Process 不用 Kestrel,Out-of-Process 用 Kestrel
- Docker/K8s:0.0.0.0:80
关键配置
C#
// 监听地址配置(五选一)
builder.WebHost.UseUrls("http://localhost:5000"); // 代码
"Urls": "http://localhost:5000" // appsettings.json
ASPNETCORE_URLS=http://localhost:5000 // 环境变量
dotnet run --urls "http://localhost:5000" // 命令行
"applicationUrl": "http://localhost:5000" // launchSettings.json
最佳实践
- ✅ 开发:使用 launchSettings.json
- ✅ 生产:使用 appsettings.json 或环境变量
- ✅ 反向代理:配置转发头中间件
- ✅ Docker:监听 0.0.0.0
- ✅ 安全:生产环境使用 Nginx/IIS 做反向代理