Add XCode skills for entity caching, ORM, and sharding ETL
|
---
name: http-server
description: >
使用 NewLife.Http.HttpServer 构建轻é‡çº§ HTTP æœåŠ¡ç«¯ï¼Œæ¶µç›–è·¯ç”±æ³¨å†Œï¼ˆMap/MapController/MapStaticFiles)ã€
委托处ç†å™¨ï¼ˆLambda ç›´æŽ¥æ˜ å°„ä¸ºè·¯ç”±ï¼‰ã€æŽ§åˆ¶å™¨å¤„ç†å™¨ï¼ˆControllerHandler)ã€é™æ€æ–‡ä»¶æœåŠ¡ï¼Œ
以åŠåŸºäºŽ NewLife.Net çš„ WebSocket æœåŠ¡ç«¯ä¸Žå®¢æˆ·ç«¯ï¼ˆWebSocketClient/WebSocketSession)。
é€‚ç”¨äºŽå†…åµŒå¼ HTTP APIã€ç‰©è”网设备管ç†ç•Œé¢ã€WebSocket 实时推é€ç‰åœºæ™¯ã€‚
argument-hint: >
è¯´æ˜Žä½ çš„ HTTP æœåŠ¡åœºæ™¯ï¼šç®€å• REST API(用 Lambda Map 或 Controller);
陿€æ–‡ä»¶æœåŠ¡ï¼›WebSocket åŒå‘推é€ï¼›è¿˜æ˜¯éœ€è¦ HTTPS(TLS)。
说明是æœåŠ¡ç«¯è¿˜æ˜¯å®¢æˆ·ç«¯ï¼Œä»¥åŠæ˜¯å¦éœ€è¦è‡ªå®šä¹‰è¯·æ±‚头/认è¯ã€‚
---
# HTTP æœåŠ¡ç«¯ä¸Ž WebSocket 技能
## 适用场景
- 在应用内嵌入轻é‡çº§ HTTP API(å¥åº·æ£€æŸ¥ã€ç®¡ç†æŽ¥å£ã€Webhook æŽ¥æ”¶ï¼‰ï¼Œæ— éœ€å¼•å…¥ ASP.NET Core。
- 物è”网设备管ç†ç•Œé¢ï¼šæä¾›é™æ€æ–‡ä»¶ + REST API,`HttpServer` 开箱å³ç”¨ã€‚
- WebSocket å®žæ—¶æ¶ˆæ¯æŽ¨é€æˆ–设备åŒå‘通信 —— `WebSocketSession`(æœåŠ¡ç«¯ï¼‰/ `WebSocketClient`(客户端)。
- 代ç 审查:确认路由注册在å¯åŠ¨é˜¶æ®µå®Œæˆï¼ˆè¿è¡ŒæœŸå¹¶å‘修改 Routes å—å…¸ä¸çº¿ç¨‹å®‰å…¨ï¼‰ã€‚
## æ ¸å¿ƒåŽŸåˆ™
1. **HttpServer 继承 NetServer**:所有 TCP 层能力(会è¯ç®¡ç†ã€ç®¡é“ç¼–è§£ç ã€APMã€æ—¥å¿—)å‡å¤ç”¨ NetServer,`HttpServer` åªè´Ÿè´£è·¯ç”±æ³¨å†Œä¸Ž HTTP å议处ç†ã€‚
2. **路由按注册顺åºåŒ¹é…**:精确匹é…优先于通é…ç¬¦ï¼ˆå« `*` 的路由 key),通é…符路由用 `IsMatch` 模糊匹é…。
3. **路由注册éžçº¿ç¨‹å®‰å…¨**:`Routes` 是普通 `Dictionary`,仅支æŒå¯åŠ¨é˜¶æ®µæ‰¹é‡æ³¨å†Œï¼Œè¿è¡ŒæœŸä¸è¦åЍæ€å¢žåˆ 路由。
4. **控制器路由约定**:`MapController<T>("/api")` 注册为 `/api/*`,控制器方法åå³è·¯ç”±åŽç¼€ï¼›æ–¹æ³•傿•°ä»Ž QueryString / Body 自动绑定。
5. **WebSocket å¤ç”¨ NetServer 管é“**:`WebSocketCodec` 作为管é“处ç†å™¨ï¼Œå¤„ç†æ¡æ‰‹å’Œå¸§ç¼–è§£ç ï¼›`WebSocketClient` 继承 `TcpSession`,自动å‘é€ Ping 心跳(默认 120 秒)。
## 执行æ¥éª¤
### ä¸€ã€æœ€ç®€ HTTP æœåŠ¡ï¼ˆLambda 路由)
```csharp
using NewLife.Http;
using NewLife.Log;
var server = new HttpServer
{
Port = 8080,
Log = XTrace.Log,
};
// æ— å‚返回
server.Map("/health", () => "OK");
// 另傿•°ï¼ˆä»Ž QueryString 自动绑定)
server.Map("/greet", (string name) => $"Hello, {name}!");
// 多å‚
server.Map("/add", (int a, int b) => a + b);
// 原始 HttpProcessDelegate(获å–完整 HttpContext)
server.Map("/raw", (HttpRequest req, HttpResponse res) =>
{
res.SetHeader("Content-Type", "text/plain");
res.WriteBody("Raw response");
});
server.Start();
// server.Stop("shutdown");
```
### äºŒã€æŽ§åˆ¶å™¨è·¯ç”±
```csharp
// 定义控制器(方法åå³è·¯ç”±ï¼Œå‚数自动绑定)
public class UserController
{
// GET /api/list?page=1
public List<User> List(int page = 1, int pageSize = 20)
=> UserService.GetPage(page, pageSize);
// POST /api/create(Body JSON 自动ååºåˆ—化为 User)
public User Create(User user)
{
UserService.Insert(user);
return user;
}
// GET /api/get?id=1
public User Get(int id) => UserService.FindById(id);
}
// 注册控制器(路由å‰ç¼€ /api/*)
server.MapController<UserController>("/api");
```
### 三ã€é™æ€æ–‡ä»¶æœåŠ¡
```csharp
// 将 ./wwwroot 目录挂载到 /static 路径
server.MapStaticFiles("/static", "./wwwroot");
// 组åˆï¼šAPI + 陿€æ–‡ä»¶
server.Map("/health", () => "OK");
server.MapController<ApiController>("/api");
server.MapStaticFiles("/", "./wwwroot"); // æ ¹è·¯å¾„å…œåº•é™æ€æ–‡ä»¶
```
### å››ã€è‡ªå®šä¹‰ IHttpHandler
```csharp
public class MyHandler : IHttpHandler
{
public void ProcessRequest(IHttpContext context)
{
var req = context.Request;
var res = context.Response;
// 读å–请求
var method = req.Method; // GET/POST/...
var path = req.Path;
var body = req.BodyStream;
// 写入å“应
res.StatusCode = 200;
res.SetHeader("Content-Type", "application/json");
res.WriteBody("{\"code\":0}");
}
}
server.Map("/custom", new MyHandler());
```
### 五ã€WebSocket æœåŠ¡ç«¯
```csharp
using NewLife.Http;
using NewLife.Net;
// HttpServer 内置对 Upgrade: websocket 的支æŒ
// åªéœ€æ³¨å†Œè·¯å¾„,会è¯ç±»ç»§æ‰¿ WebSocketSession
public class ChatSession : WebSocketSession
{
protected override void OnTextMessage(String text)
{
// 收到文本消æ¯
XTrace.WriteLine("收到:{0}", text);
// 广æ’给所有连接
Server.SendAllMessage(text);
}
protected override void OnConnected()
{
base.OnConnected();
SendText("Welcome!");
}
}
var httpServer = new HttpServer { Port = 8080 };
httpServer.Map("/ws", new WebSocketSessionHandler<ChatSession>());
httpServer.Start();
```
### å…ã€WebSocket 客户端
```csharp
using NewLife.Net;
var client = new WebSocketClient("ws://127.0.0.1:8080/ws");
client.KeepAlive = TimeSpan.FromSeconds(30); // 心跳间隔
// 设置自定义请求头(认è¯ï¼‰
client.SetRequestHeader("Authorization", "Bearer " + token);
// 收消æ¯
client.Received += (sender, e) =>
{
if (e.Message is WebSocketMessage msg)
{
switch (msg.Type)
{
case WebSocketMessageType.Text:
Console.WriteLine(msg.Payload?.ToStr());
break;
case WebSocketMessageType.Binary:
ProcessBinary(msg.Payload);
break;
}
}
};
await client.OpenAsync();
// å‘é€
await client.SendTextAsync("Hello!");
await client.SendBinaryAsync(binaryPacket);
// å…³é—
client.Dispose();
```
### 七ã€HTTPS / TLS
```csharp
// HttpServer 继承 NetServer,TLS é…置方å¼ç›¸åŒ
server.SslProtocol = SslProtocols.Tls12;
server.Certificate = new X509Certificate2("server.pfx", "password");
// Port 建议改为 443
```
## é‡ç‚¹æ£€æŸ¥é¡¹
- [ ] 路由是å¦åœ¨ `server.Start()` 之å‰å®Œæˆæ³¨å†Œï¼ˆRoutes å—å…¸éžçº¿ç¨‹å®‰å…¨ï¼Œè¿è¡ŒæœŸä¿®æ”¹æœ‰å¹¶å‘风险)?
- [ ] `MapController` 的控制器方法是å¦ä¸º `public`ï¼ˆéž public 方法ä¸ä¼šè¢«è·¯ç”±æ³¨å†Œï¼‰ï¼Ÿ
- [ ] å§”æ‰˜è·¯ç”±çš„å‚æ•°ç±»åž‹ä¸Ž QueryString å—æ®µå是å¦åŒ¹é…(大å°å†™ä¸æ•æ„Ÿï¼Œä½†å‚æ•°å需对应)?
- [ ] WebSocket `WebSocketCodec.UserPacket = false` 时,`e.Message` 是 `WebSocketMessage` 而éžåŽŸå§‹å—节—— Handler 里的类型æ–è¨€æ˜¯å¦æ£ç¡®ï¼Ÿ
- [ ] `WebSocketClient.KeepAlive` 是å¦ä¸ŽæœåŠ¡ç«¯è¶…æ—¶é…置互相兼容(客户端 Ping 频率 < æœåŠ¡ç«¯ SessionTimeout)?
- [ ] 陿€æ–‡ä»¶æ˜¯å¦ä½¿ç”¨äº† `MapStaticFiles` è€Œéžæ‰‹åŠ¨è¯»å–æ–‡ä»¶ï¼ˆåŽè€…绕过了路径é历防护)?
## è¾“å‡ºè¦æ±‚
- **HTTP æœåŠ¡ç«¯**:`HttpServer`(`NewLife.Http`)—— 继承 `NetServer`ï¼›`Map`/`MapController`/`MapStaticFiles` 三ç§è·¯ç”±æ³¨å†Œæ–¹å¼ã€‚
- **处ç†å™¨æŽ¥å£**:`IHttpHandler`(自定义)ã€`DelegateHandler`(Lambda)ã€`ControllerHandler`(控制器)。
- **WebSocket æœåŠ¡ç«¯**:`WebSocketSession`(继承 `NetSession`);在 HttpServer 上注册路径。
- **WebSocket 客户端**:`WebSocketClient`(继承 `TcpSession`,`NewLife.Net`);`SendTextAsync`/`SendBinaryAsync`;自动 Ping 心跳。
- **æ¶ˆæ¯æ¨¡åž‹**:`WebSocketMessage`(`NewLife.Http`)—— `Type`/`Payload`/`CloseStatus`。
## å‚考资料
å‚考示例与模å¼è¯æ®è§ `references/newlife-httpserver-patterns.md`。
|