You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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包解析多部分表单:

  1. 先在pubspec.yaml添加依赖:
dependencies:
  shelf_multipart: ^1.0.0
  1. 代码示例:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:50:05