使用Shelf框架时如何获取POST表单数据及上传文件?
使用Shelf处理POST表单数据与文件上传指南
Shelf本身是个轻量级HTTP框架,核心只提供最基础的请求/响应处理能力,表单解析、文件上传这类功能都被放到了扩展包里,这就是你没法直接从Request拿到表单数据的原因。下面直接给你实用的解决方案:
处理普通表单数据(application/x-www-form-urlencoded)
方法1:用shelf_plus简化操作
shelf_plus是Shelf的增强库,封装了常用功能,能直接解析表单:
import 'package:shelf_plus/shelf_plus.dart'; void main() { var app = Router().plus; app.post('/submit', (Request request) async { // 直接获取表单键值对 var formData = await request.bodyAsFormData; String username = formData['username']!; String password = formData['password']!; return Response.ok('Received: $username, $password'); }); serve(app, 'localhost', 8080); }
方法2:手动解析(无额外依赖)
如果不想加扩展包,可以自己读取请求体后解析:
import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; void main() { var router = Router(); router.post('/submit', (Request request) async { if (request.headers['content-type'] == 'application/x-www-form-urlencoded') { // 读取请求体字符串 String body = await request.readAsString(); // 解析成键值对 Map<String, String> formData = Uri.splitQueryString(body); String? username = formData['username']; String? password = formData['password']; return Response.ok('Received: $username, $password'); } return Response.badRequest(body: 'Invalid content type'); }); serve(router, 'localhost', 8080); }
处理文件上传(multipart/form-data)
这种场景需要用shelf_multipart包解析多部分表单:
- 先在pubspec.yaml添加依赖:
dependencies: shelf_multipart: ^1.0.0
- 代码示例:
import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; import 'package:shelf_multipart/shelf_multipart.dart'; import 'dart:io'; void main() { var router = Router(); router.post('/upload', (Request request) async { if (!isMultipartRequest(request)) { return Response.badRequest(body: 'Not a multipart request'); } // 遍历所有表单部分 var parts = await request.parts; for (var part in parts) { if (part.isFile) { // 保存上传的文件到本地 var file = File('./uploads/${part.filename}'); await part.pipe(file.openWrite()); print('Saved file: ${part.filename}'); } else { // 处理普通表单字段 String value = await part.readAsString(); print('Field ${part.name}: $value'); } } return Response.ok('Upload completed'); }); serve(router, 'localhost', 8080); }
关于params属性的说明
Shelf的params确实是用来获取路径参数的(比如路由/user/:id里的id),这是框架的设计选择——核心库只聚焦路由匹配和基础HTTP交互,把请求体解析这类功能交给扩展包,保持核心的轻量和灵活。这种设计和全量框架不同,但好处是你可以按需选择需要的扩展,不会引入冗余功能。
内容的提问来源于stack exchange,提问作者Sunder
相关产品推荐
相关产品推荐

