#Flutter中使用Shelf做服务器框架

写在前面

Shelf 是 Dart 生态系统中的轻量级 Web 服务器框架,专为构建 HTTP 服务器和 API 代理而设计。为什么我会使用到他,因为我接到了一个新的需求

即设备B不能直接往服务器发送请求,要通过设备A进行服务转发。因此我需要在设备A中启动一个服务来接收B的请求并转发出去。

复制代码
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   设备B     │      │   设备A     │     │   服务器    │
│ (代理设备)   │────▶│ (主设备)    │────▶│             │
│             │     │ 代理服务器  │     │             │
└─────────────┘     │ Port: 8088  │     └─────────────┘
                    └─────────────┘

Shelf 核心特性

  • 轻量级:最小化依赖,快速启动
  • Dart 原生:与 Flutter 完美集成
  • 异步友好:原生支持 async/await
  • 中间件架构:可扩展的请求处理管道
  • 类型安全:强类型支持,编译时检查

依赖配置

pubspec.yaml 配置

yaml 复制代码
dependencies:
  shelf: ^1.4.1
  shelf_router: ^1.1.4
  shelf_static: ^1.1.2  # 可选:静态文件服务

导入语句

dart 复制代码
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_router/shelf_router.dart';

怎么使用

1. Handler(处理器)

Shelf 的核心是 Handler - 一个处理 HTTP 请求并返回响应的函数:

dart 复制代码
typedef Handler = FutureOr<Response> Function(Request request);

2. Request(请求对象)

封装 HTTP 请求的所有信息:

dart 复制代码
shelf.Request request = ...;

// 获取请求信息
String method = request.method;           // GET, POST, etc.
Uri url = request.url;                   // 请求URL
Map<String, String> headers = request.headers;  // 请求头
Map<String, String> params = request.params;    // 路径参数

3. Response(响应对象)

创建 HTTP 响应:

dart 复制代码
shelf.Response response = shelf.Response(
  200,                                    // 状态码
  headers: {'Content-Type': 'application/json'},
  body: '{"message": "Hello World"}',
);

在代理服务器中的应用

项目中的使用场景

比如在在我代理服务器中,Shelf 主要用于:

  1. HTTP 服务器:监听端口,接收代理设备请求
  2. 路由管理:将不同 API 路径分发到对应处理器
  3. 请求转发:将客户端请求转发到目标服务器
  4. 响应代理:将目标服务器响应返回给客户端

核心代码结构

dart 复制代码
class ProxyService {
  static HttpServer? _server;

  /// 启动代理服务器
  static Future<void> startProxy() async {
    final router = Router();

    // 注册 API 路由
    router.all('/apis/<path|.*>', _handleApiRequest);

    // 启动 HTTP 服务器
    _server = await io.serve(router, '0.0.0.0', 8088);
  }

  /// 处理 API 请求
  static Future<shelf.Response> _handleApiRequest(shelf.Request request) async {
    // 1. 解析请求
    final path = request.params['path'] ?? '';
    final headers = Map<String, String>.from(request.headers);

    // 2. 转发请求到目标服务器
    final response = await http.get('target-url', headers: headers);

    // 3. 返回响应
    return shelf.Response(response.statusCode, body: response.body);
  }
}

API 说明

服务器启动和关闭

io.serve() - 启动服务器
dart 复制代码
HttpServer server = await io.serve(
  handler,           // 请求处理器
  '0.0.0.0',        // 监听地址(0.0.0.0 监听所有接口)
  8088,              // 监听端口
);
server.close() - 关闭服务器
dart 复制代码
await server.close();
// 优雅关闭,完成当前请求后再停止

路由管理

Router 基本使用
dart 复制代码
final router = Router();

// 注册路由
router.get('/users', getUsersHandler);
router.post('/users', createUserHandler);
router.get('/users/<id>', getUserByIdHandler);
路由匹配语法
dart 复制代码
// 基本路径
router.get('/api/users', handler);

// 路径参数
router.get('/users/<id>', (Request request) {
  String userId = request.params['id']!;
  return Response.ok('User ID: $userId');
});

// 通配符匹配
router.all('/api/<path|.*>', apiHandler);

// 正则表达式(通过自定义中间件)
HTTP 方法支持
dart 复制代码
router.get('/path', handler);     // GET 请求
router.post('/path', handler);    // POST 请求
router.put('/path', handler);     // PUT 请求
router.delete('/path', handler);  // DELETE 请求
router.patch('/path', handler);   // PATCH 请求
router.head('/path', handler);    // HEAD 请求
router.options('/path', handler); // OPTIONS 请求
router.all('/path', handler);     // 匹配所有方法

请求处理

Request 对象属性
dart 复制代码
Future<shelf.Response> handler(shelf.Request request) async {
  // 请求方法
  String method = request.method;  // 'GET', 'POST', etc.

  // 请求URL
  Uri url = request.url;           // 相对URL
  String path = url.path;          // 路径部分
  String query = url.query;        // 查询字符串

  // 请求头
  Map<String, String> headers = request.headers;
  String? contentType = headers['content-type'];

  // 路径参数(来自路由匹配)
  Map<String, String> params = request.params;
  String? userId = params['id'];

  // 请求体
  String body = await request.readAsString();

  // 处理请求...
}
读取请求体
dart 复制代码
// 读取为字符串
String body = await request.readAsString();

// 读取为字节
List<int> bytes = await request.read().expand((chunk) => chunk).toList();

// 读取 JSON
Map<String, dynamic> jsonData = json.decode(await request.readAsString());

响应创建

Response 静态方法
dart 复制代码
// 常用响应
return shelf.Response.ok('Success');                    // 200 OK
return shelf.Response.notFound('Not Found');            // 404 Not Found
return shelf.Response.forbidden('Forbidden');           // 403 Forbidden
return shelf.Response.internalServerError('Error');     // 500 Internal Server Error

// 自定义响应
return shelf.Response(
  201,                                                   // 状态码
  headers: {
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': '*',
  },
  body: json.encode({'id': 123, 'name': 'John'}),
);
Response 构造函数参数
dart 复制代码
shelf.Response(
  statusCode,              // HTTP 状态码 (int)
  headers: {},            // 响应头 (Map<String, String>)
  body: '',               // 响应体 (String, List<int>, Stream, etc.)
  encoding: utf8,         // 文本编码 (Encoding)
  context: {},            // 上下文数据 (Map<String, Object>)
);

中间件(Middleware)

内置中间件

dart 复制代码
import 'package:shelf/shelf.dart' as shelf;

// 日志中间件
final handler = const shelf.Pipeline()
    .addMiddleware(shelf.logRequests())
    .addHandler(app);

// CORS 中间件
Middleware corsHeaders = (Handler handler) {
  return (Request request) async {
    final response = await handler(request);
    return response.change(headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
      'Access-Control-Allow-Headers': 'Content-Type',
    });
  };
};

// 自定义中间件
Middleware authentication = (Handler handler) {
  return (Request request) async {
    final token = request.headers['authorization'];
    if (token == null) {
      return shelf.Response.forbidden('No token provided');
    }
    // 验证 token...
    return handler(request);
  };
};

// 使用中间件
final app = const shelf.Pipeline()
    .addMiddleware(corsHeaders)
    .addMiddleware(authentication)
    .addMiddleware(shelf.logRequests())
    .addHandler(router);

完整示例

简单 HTTP 服务器

dart 复制代码
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;

void main() async {
  // 创建处理器
  shelf.Response handler(shelf.Request request) {
    return shelf.Response.ok('Hello, ${request.url.path}!');
  }

  // 启动服务器
  final server = await io.serve(handler, 'localhost', 8080);
  print('Server listening on http://localhost:8080');
}

REST API 服务器

dart 复制代码
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_router/shelf_router.dart';

class ApiServer {
  Router get router {
    final router = Router();

    router.get('/api/users', (shelf.Request request) {
      return shelf.Response.ok(
        json.encode([{'id': 1, 'name': 'John'}, {'id': 2, 'name': 'Jane'}]),
        headers: {'Content-Type': 'application/json'},
      );
    });

    router.post('/api/users', (shelf.Request request) async {
      final body = await request.readAsString();
      final user = json.decode(body);
      // 保存用户...
      return shelf.Response(201, body: json.encode({'id': 3, ...user}));
    });

    router.get('/api/users/<id>', (shelf.Request request) {
      final id = request.params['id'];
      return shelf.Response.ok(json.encode({'id': id, 'name': 'User $id'}));
    });

    return router;
  }

  Future<void> start() async {
    final server = await io.serve(router, '0.0.0.0', 8080);
    print('API Server running on http://localhost:8080');
  }
}

代理服务器示例

dart 复制代码
class ProxyServer {
  Future<shelf.Response> proxyHandler(shelf.Request request) async {
    // 构建目标URL
    final targetUrl = 'https://api.example.com${request.url}';

    // 转发请求
    final response = await http.get(
      Uri.parse(targetUrl),
      headers: request.headers,
    );

    // 返回响应
    return shelf.Response(
      response.statusCode,
      headers: response.headers,
      body: response.body,
    );
  }

  Future<void> start() async {
    final router = Router();
    router.all('/api/<path|.*>', proxyHandler);

    final server = await io.serve(router, '0.0.0.0', 8088);
    print('Proxy server running on port 8088');
  }
}
相关推荐
IT陈图图2 小时前
基于 Flutter × OpenHarmony 图书馆管理系统之构建借阅记录模块
flutter·正则表达式·openharmony
时光慢煮2 小时前
基于 Flutter × OpenHarmony 图书馆管理系统之构建书籍列表
flutter·华为·开源·openharmony
LawrenceLan4 小时前
Flutter 零基础入门(二十一):Container、Padding、Margin 与装饰
开发语言·前端·flutter·dart
IT陈图图4 小时前
跨端智慧图书馆:Flutter × OpenHarmony 下的读者管理模块构建实践
flutter·华为·鸿蒙·openharmony
IT陈图图4 小时前
基于 Flutter × OpenHarmony 的图书馆管理系统之书籍卡片模块构建
flutter·开源·鸿蒙·openharmony
IT陈图图4 小时前
优雅管理,智慧阅读:基于 Flutter × OpenHarmony 构建图书馆读者列表模块
flutter·华为·鸿蒙·openharmony
2401_zq136y034 小时前
Flutter for OpenHarmony:从零搭建今日资讯App(二十九)深色模式适配全攻略
flutter
时光慢煮5 小时前
从零构建跨端图书馆管理页面:Flutter × OpenHarmony 实战指南-架构搭建
flutter·开源·openharmony
向前V5 小时前
Flutter for OpenHarmony数独游戏App实战:单元格交互与选中
flutter·游戏·交互