Kestrel监听-Http服务

Kestrel 完整笔记

目录

  1. [Kestrel 是什么](#Kestrel 是什么 "#1-kestrel-%E6%98%AF%E4%BB%80%E4%B9%88")
  2. 为什么叫"监听"
  3. [Kestrel 的真实工作](#Kestrel 的真实工作 "#3-kestrel-%E7%9A%84%E7%9C%9F%E5%AE%9E%E5%B7%A5%E4%BD%9C")
  4. 系统主地址概念
  5. 编辑工具的地址
  6. 不同部署场景的地址配置
  7. 完整配置示例

1. Kestrel 是什么

1.1 官方定义

Kestrel = ASP.NET Core 内置的跨平台 Web 服务器

1.2 通俗理解

Kestrel = 监听服务 + 构建服务

arduino 复制代码
Kestrel 的双重职责:
​
1. 监听服务(Listening Service)
   - 在网络端口上监听
   - 等待和接收 HTTP 请求
   - 这是"守门员"的角色
​
2. 构建服务(Building Service)
   - 构建整个系统的 HTTP 服务能力
   - 提供 HTTP 协议处理
   - 搭建请求-响应的基础设施
   - 这是"建筑工人"的角色

Kestrel = 你的程序的 HTTP 服务引擎

它是一个软件组件,负责:

1.3 形象比喻

ini 复制代码
你的 ASP.NET Core 程序 = 一家餐厅
​
Kestrel = 餐厅的前台接待员
    ├─ 在门口等待客人(监听端口)
    ├─ 接待客人进门(接收请求)
    ├─ 理解客人需求(解析HTTP)
    ├─ 转告厨房(传给你的代码)
    ├─ 接收厨房做好的菜(接收响应)
    └─ 送给客人(发送响应)
​
你的业务代码 = 厨房(处理业务逻辑)

1.4 技术架构中的位置

css 复制代码
客户端(浏览器/APP)
    ↓ HTTP 请求
[Kestrel] ← 这是网络边界
    ↓
[ASP.NET Core 请求管道]
    ├─ 路由
    ├─ 认证
    ├─ 授权
    └─ 中间件
        ↓
    [你的控制器/代码]
        ↓ 返回结果
[ASP.NET Core 管道处理]
    ↓
[Kestrel]
    ↓ HTTP 响应
客户端

1.5 代码中的 Kestrel

ini 复制代码
var builder = WebApplication.CreateBuilder(args);
​
builder.Services.AddControllers();
​
var app = builder.Build();
​
app.MapControllers();
​
app.Run();  // ← 这行代码启动 Kestrel

当执行 app.Run() 时:

markdown 复制代码
1. 托管系统启动
2. Kestrel 被初始化
3. Kestrel 绑定到指定的网络端口
4. Kestrel 开始"监听"
5. 控制台输出:Now listening on: http://localhost:5000
6. 程序进入等待状态,不会退出
7. 每当有 HTTP 请求到来,Kestrel 接收并处理

2. 为什么叫"监听"

2.1 "监听"的含义

监听(Listen)= 在网络端口上等待连接

这是网络编程的标准术语。

2.2 底层原理

arduino 复制代码
// 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();  // 阻塞等待
    // 处理客户端请求...
}
​
​

网络通信的基本原理:

lua 复制代码
客户端(浏览器)                    服务器(你的程序)
      |                                    |
      | 1. 我要连接 192.168.1.100:5000     |
      |--------------------------------→   |
      |                                    | 2. 检查:有程序在监听 5000 端口吗?
      |                                    |    - 有 → 接受连接
      |                                    |    - 没有 → 拒绝连接
      |   3. ←---------------------------- |
      |        连接建立                     |

如果没有监听:

yaml 复制代码
客户端连接 → 服务器 5000 端口 → 没有程序监听 → 连接失败
浏览器显示:ERR_CONNECTION_REFUSED(连接被拒绝)

2.3 "监听"的三个步骤

markdown 复制代码
1. Bind(绑定)
   - Kestrel 告诉操作系统:"我要用 5000 端口"
   - 操作系统分配端口给 Kestrel

2. Listen(监听)
   - Kestrel 告诉操作系统:"开始接收这个端口的连接"
   - 操作系统将到达该端口的请求放入队列

3. Accept(接受)
   - Kestrel 从队列中取出连接
   - 开始处理 HTTP 请求

2.4 为什必须"监听"

网络通信的基本规则:

markdown 复制代码
客户端要连接服务器,必须知道:
1. 服务器的 IP 地址
2. 服务器的端口号

服务器要接受连接,必须:
1. 在指定端口上"监听"
2. 等待客户端连接

示例:

markdown 复制代码
用户在浏览器输入: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:

bash 复制代码
netstat -ano | findstr :5000
# 输出:TCP    0.0.0.0:5000    0.0.0.0:0    LISTENING    12345
#              ↑                              ↑
#           监听端口                       监听状态

Linux:

perl 复制代码
netstat -tuln | grep :5000
# 或
ss -tuln | grep :5000

2.6 监听范围

arduino 复制代码
// 只监听本机回环接口
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 服务处理引擎

markdown 复制代码
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 请求处理全流程

ini 复制代码
客户端发送: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 代码验证

javascript 复制代码
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 服务

从网络字节到你的代码:

sql 复制代码
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. 发送给客户端

你的代码只需要:

javascript 复制代码
app.MapGet("/api/users", () => new[] { "User1", "User2" });

Kestrel 帮你做了所有底层工作!

3.5 Kestrel 构建的 HTTP 能力

HTTP/1.1 支持
arduino 复制代码
// Kestrel 自动支持
// - Keep-Alive 连接复用
// - 分块传输编码
// - 管道化请求
HTTP/2 支持
ini 复制代码
builder.WebHost.ConfigureKestrel(options =>
{
    options.Listen(IPAddress.Any, 5001, listenOptions =>
    {
        listenOptions.UseHttps();
        listenOptions.Protocols = HttpProtocols.Http2;
    });
});

// 支持:
// - 多路复用
// - 服务器推送
// - 头部压缩
HTTP/3 支持 (QUIC)
ini 复制代码
builder.WebHost.ConfigureKestrel(options =>
{
    options.Listen(IPAddress.Any, 5001, listenOptions =>
    {
        listenOptions.UseHttps();
        listenOptions.Protocols = HttpProtocols.Http3;
    });
});
WebSocket 支持
ini 复制代码
app.UseWebSockets();

app.Map("/ws", async context =>
{
    if (context.WebSockets.IsWebSocketRequest)
    {
        var webSocket = await context.WebSockets.AcceptWebSocketAsync();
        // Kestrel 处理 WebSocket 协议升级
    }
});
HTTPS/TLS 支持
ini 复制代码
builder.WebHost.ConfigureKestrel(options =>
{
    options.Listen(IPAddress.Any, 5001, listenOptions =>
    {
        listenOptions.UseHttps("cert.pfx", "password");
        // Kestrel 处理 TLS 握手和加密
    });
});

3.6 Kestrel 不做什么

diff 复制代码
❌ 路由匹配(由路由中间件做)
❌ 身份验证(由认证中间件做)
❌ 授权检查(由授权中间件做)
❌ 业务逻辑(由你的代码做)
❌ 数据库操作(由你的代码做)
❌ 静态文件服务(由静态文件中间件做)

✅ Kestrel 只负责 HTTP 协议层的事情


有了 Kestrel,你的程序:

- ✅ 成为一个 Web 服务器
- ✅ 可以处理 HTTP/HTTPS 请求
- ✅ 支持 HTTP/1.1, HTTP/2, HTTP/3
- ✅ 可以对外提供 API/网站服务

4. 系统主地址概念

4.1 什么是"系统主地址"

系统主地址 = Kestrel 监听的地址 = 整个应用的网络入口

arduino 复制代码
builder.WebHost.UseUrls("http://localhost:5000");
//                       ↑
//                  这就是系统主地址

4.2 为什么叫"主地址"

因为所有功能都基于这个地址:

bash 复制代码
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(代码)
ini 复制代码
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
json 复制代码
{
  "Urls": "http://localhost:8000"
}
ini 复制代码
var builder = WebApplication.CreateBuilder(args);
// ASP Net Core默认 appsettings.json 中的 "Urls"关键字

var app = builder.Build();
app.Run();
方式3:环境变量
ini 复制代码
export ASPNETCORE_URLS="http://localhost:8000"
dotnet MyApp.dll
方式4:命令行
arduino 复制代码
dotnet MyApp.dll --urls "http://localhost:8000"

4.4 主地址的范围

ruby 复制代码
// 只监听本地(开发环境)
"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 多个主地址

ruby 复制代码
// 同时监听 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

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 启动时:

markdown 复制代码
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 运行

arduino 复制代码
按 F5 启动
→ 使用 launchSettings.json 的地址
→ 监听 http://localhost:5000

测试2:命令行运行

arduino 复制代码
dotnet run
→ 也会读取 launchSettings.json(如果存在)
→ 监听 http://localhost:5000

测试3:发布后运行

bash 复制代码
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/环境变量 所有环境

如果同时配置:

json 复制代码
// 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)

目标: 只有开发者自己访问

配置:

json 复制代码
// launchSettings.json
{
  "profiles": {
    "Development": {
      "applicationUrl": "http://localhost:5000"
    }
  }
}

特点:

  • 只监听 localhost
  • 外部无法访问
  • 安全

访问:

arduino 复制代码
开发者访问:http://localhost:5000 ✅
同事访问:  http://你的电脑IP:5000 ❌ 无法访问

6.2 场景2:本地开发(允许局域网访问)

目标: 让同事/测试人员访问

配置:

ini 复制代码
var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsDevelopment())
{
    // 监听所有网卡
    builder.WebHost.UseUrls("http://*:5000");
}

var app = builder.Build();
app.Run();

访问:

arduino 复制代码
你自己:     http://localhost:5000 ✅
同事:       http://192.168.1.100:5000 ✅
外网用:   ❌ 无法访问(局域网内)

6.3 场景3:Linux 服务器直接部署

目标: 程序直接暴露在公网

配置:

json 复制代码
// appsettings.Production.json
{
  "Urls": "http://*:80"
}
bash 复制代码
# 部署
dotnet MyApp.dll
# Kestrel 监听 80 端口

架构:

arduino 复制代码
用户浏览器
    ↓
http://47.103.25.88:80
    ↓
Kestrel 监听 0.0.0.0:80
    ↓
你的程序

问题:

  • ❌ 没有 HTTPS(不安全)
  • ❌ 端口直接暴露
  • ❌ 无法负载均衡

6.4 场景4:Nginx 反向代理(推荐)

目标: 生产环境标准部署

架构:

arduino 复制代码
用户浏览器
    ↓
https://myapp.com (443端口)
    ↓
Nginx (处理 HTTPS, 负载均衡)
    ↓
http://localhost:5000 (内网)
    ↓
Kestrel 监听 localhost:5000
    ↓
你的程序

Nginx 配置: /etc/nginx/sites-available/myapp

ini 复制代码
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 配置:

json 复制代码
// appsettings.Production.json
{
  "Urls": "http://localhost:5000"
}
ini 复制代码
// 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(进程内)

架构:

markdown 复制代码
用户请求
    ↓
IIS (80/443端口)
    ↓
你的程序(运行在IIS进程内)
    ↓
不使用 Kestrel ❌

web.config:

xml 复制代码
<?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:

ini 复制代码
var builder = WebApplication.CreateBuilder(args);

// UseUrls 会被忽略
// builder.WebHost.UseUrls("..."); // ← 无效

var app = builder.Build();
app.Run();

特点:

  • ❌ Kestrel 不工作
  • ✅ IIS 直接处理 HTTP
  • ✅ 性能最好
  • ❌ 只能 Windows

模式B:Out-of-Process(进程外)

架构:

arduino 复制代码
用户请求
    ↓
IIS (80/443端口)
    ↓
转发到 http://localhost:随机端口
    ↓
Kestrel 监听(独立进程)
    ↓
你的程序

web.config:

xml 复制代码
<aspNetCore processPath="dotnet" 
            arguments=".\MyApp.dll" 
            hostingModel="outofprocess">
<!--        ↑ Out-of-Process 模式 -->
</aspNetCore>

Program.cs:

ini 复制代码
var builder = WebApplication.CreateBuilder(args);

// IIS 会自动设置端口,不需要手动配置
// builder.WebHost.UseUrls("..."); // 可选

var app = builder.Build();
app.Run();

特点:

  • ✅ 使用 Kestrel
  • ✅ IIS 转发请求
  • ✅ 程序独立进程

6.6 场景6:Docker 容器

Dockerfile:

bash 复制代码
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 配置:

ini 复制代码
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();

运行:

shell 复制代码
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:

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

架构:

yaml 复制代码
用户请求
    ↓
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 开发环境配置

scss 复制代码
// 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

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

json 复制代码
{
  "Urls": "http://localhost:5000",
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  }
}

Program.cs:

C#

ini 复制代码
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

ini 复制代码
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#

scss 复制代码
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#

ini 复制代码
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 核心要点

  1. Kestrel 是什么

    • ASP.NET Core 内置的 HTTP 服务器
    • 负责处理所有 HTTP 请求和响应
  2. 为什么叫监听

    • 在网络端口上等待连接
    • 网络编程的标准术语
  3. 系统主地址

    • Kestrel 监听的地址
    • 整个应用的网络入口
    • 所有功能都基于这个地址
  4. 编辑工具地址

    • launchSettings.json 中的配置
    • 只在 IDE 开发时生效
    • 优先级低于代码配置
  5. 部署场景

    • 开发:localhost,安全隔离
    • 直接部署:0.0.0.0,监听所有IP
    • 反向代理:localhost,内网监听
    • IIS:In-Process 不用 Kestrel,Out-of-Process 用 Kestrel
    • Docker/K8s:0.0.0.0:80

关键配置

C#

arduino 复制代码
// 监听地址配置(五选一)
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 做反向代理
相关推荐
青云计划14 小时前
知光项目知文发布模块
java·后端·spring·mybatis
Victor35614 小时前
MongoDB(9)什么是MongoDB的副本集(Replica Set)?
后端
Victor35614 小时前
MongoDB(8)什么是聚合(Aggregation)?
后端
yeyeye11116 小时前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
Tony Bai16 小时前
告别 Flaky Tests:Go 官方拟引入 testing/nettest,重塑内存网络测试标准
开发语言·网络·后端·golang·php
+VX:Fegn089517 小时前
计算机毕业设计|基于springboot + vue鲜花商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
程序猿阿伟17 小时前
《GraphQL批处理与全局缓存共享的底层逻辑》
后端·缓存·graphql
小小张说故事17 小时前
SQLAlchemy 技术入门指南
后端·python
识君啊17 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端
想用offer打牌18 小时前
MCP (Model Context Protocol) 技术理解 - 第五篇
人工智能·后端·mcp