Flutter文件上传插件shelf_multipart的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter文件上传插件shelf_multipart的使用

shelf_multipart 插件用于解析 multipartmultipart/form-data 请求,为 shelf handlers 提供了处理多部分请求的能力。本文将详细介绍如何使用该插件进行文件上传,并提供完整的示例代码。

处理多部分请求

多部分请求由 MultipartRequest 扩展类型表示。要检查一个请求是否是多部分请求,可以使用 MultipartRequest.ofRequest.multipart() 扩展方法。

import 'package:shelf_multipart/shelf_multipart.dart';
import 'package:shelf/shelf.dart';

Future<Response> myHandler(Request request) async {
  if (request.multipart() case var multipart?) {
    // 遍历构成此请求的部分:
    await for (final part in multipart.parts) {
      // 通过 part.headers 可以获取到头部信息:
      final headers = part.headers;
      // part 实现了 `Stream<List<int>>` 接口,可用于读取数据。
      // 你也可以使用 `part.readBytes()` 或 `part.readString()`
      final content = await part.readString();
      print('Part Content: $content');
    }
  } else {
    return Response(401); // 不是多部分请求
  }
}

处理 multipart/form-data

由于表单数据也是作为多部分请求发送的,因此该包提供了读取表单数据的方法:

if (request.formData() case var form?) {
  // 将所有表单参数读入单个映射中:
  final parameters = <String, String>{};
  await for (final formData in form.formData) {
    parameters[formData.name] = await formData.part.readString();
  }
  print('Form Data Parameters: $parameters');
}

完整示例代码

下面是一个完整的示例代码,展示了如何使用 shelf_multipart 插件来处理文件上传请求:

import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_multipart/shelf_multipart.dart';

Future<void> main() async {
  // 启动服务器并监听端口8080
  await shelf_io.serve(_handler, 'localhost', 8080);
  print('Listening on localhost:8080. Try the following to see it in action ');
  print('  curl -F user=myuser -F password=passw0rd http://localhost:8080');
  print(
      '  curl -H "Content-Type: multipart/mixed" -F "request={"param1": "value1"};type=application/json" http://localhost:8080');
}

Future<Response> _handler(Request request) async {
  if (request.formData() case var form?) {
    final description = StringBuffer('Parsed form multipart request\n');

    await for (final formData in form.formData) {
      description.writeln('${formData.name}: ${await formData.part.readString()}');
    }

    return Response.ok(description.toString());
  } else if (request.multipart() case var multipart?) {
    final description = StringBuffer('Regular multipart request\n');

    await for (final part in multipart.parts) {
      description.writeln('new part');

      part.headers.forEach((key, value) => description.writeln('Header $key=$value'));
      final content = await part.readString();
      description.writeln('content: $content');

      description.writeln('end of part');
    }

    return Response.ok(description.toString());
  } else {
    return Response.ok('Not a multipart request');
  }
}

如何测试

  1. 启动服务器:运行上述代码,启动本地服务器。
  2. 使用 curl 测试
    • 发送包含用户名和密码的表单数据:
      curl -F user=myuser -F password=passw0rd http://localhost:8080
      
    • 发送包含 JSON 数据的多部分请求:
      curl -H "Content-Type: multipart/mixed" -F "request={\"param1\": \"value1\"};type=application/json" http://localhost:8080
      

通过以上步骤,您可以成功地使用 shelf_multipart 插件来处理文件上传和其他多部分请求。希望这个示例能帮助您更好地理解和使用 shelf_multipart 插件。


更多关于Flutter文件上传插件shelf_multipart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter文件上传插件shelf_multipart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个使用 shelf_multipart 插件在 Flutter 中实现文件上传的示例代码。shelf_multipart 插件通常用于 Dart 后端服务来处理文件上传,但这里我们将关注如何在 Flutter 前端构建文件上传功能。实际上,Flutter 前端通常不会直接使用 shelf_multipart,而是与后端服务进行通信来上传文件。

假设你有一个 Dart 后端服务使用 shelfshelf_multipart 来处理文件上传,下面是如何在 Flutter 前端实现文件上传的示例。

1. 设置 Flutter 项目

首先,确保你已经设置了一个 Flutter 项目。如果没有,使用以下命令创建一个新的 Flutter 项目:

flutter create file_upload_app
cd file_upload_app

2. 添加依赖

pubspec.yaml 文件中添加 dio 依赖,这是一个流行的 HTTP 客户端库,用于在 Flutter 中发送请求:

dependencies:
  flutter:
    sdk: flutter
  dio: ^4.0.0  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

3. 创建文件上传界面

lib 目录下创建一个新的 Dart 文件,例如 upload_screen.dart,并添加以下代码:

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';

class UploadScreen extends StatefulWidget {
  @override
  _UploadScreenState createState() => _UploadScreenState();
}

class _UploadScreenState extends State<UploadScreen> {
  final _picker = ImagePicker();
  File? _imageFile;

  Future<void> _pickImage() async {
    final pickedFile = await _picker.pickImage(source: ImageSource.camera);

    if (pickedFile != null) {
      setState(() {
        _imageFile = File(pickedFile.path);
      });
    }
  }

  Future<void> _uploadFile() async {
    if (_imageFile == null) return;

    final storage = getApplicationDocumentsDirectory();
    final fileName = '${storage.path}/${_imageFile!.basename}';
    final file = await _imageFile!.copy(fileName);

    final formData = FormData.fromMap({
      'file': await MultipartFile.fromFile(file.path,
          filename: file.basename,
          contentType: MediaType.parse('image/jpeg')),
    });

    try {
      final response = await Dio().post('http://your-backend-url/upload', data: formData);
      print(response.data);
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('File Upload'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _imageFile == null
                ? Text('No image selected.')
                : Image.file(_imageFile!),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _pickImage,
              child: Text('Pick Image'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _uploadFile,
              child: Text('Upload'),
            ),
          ],
        ),
      ),
    );
  }
}

4. 更新主应用文件

lib/main.dart 文件中,更新代码如下以包含新的上传屏幕:

import 'package:flutter/material.dart';
import 'upload_screen.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'File Upload App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: UploadScreen(),
    );
  }
}

5. Dart 后端示例(可选)

为了完整性,这里提供一个简单的 Dart 后端示例,使用 shelfshelf_multipart 来处理文件上传:

import 'dart:io';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import 'package:shelf_multipart/shelf_multipart.dart';

void main() async {
  final router = Router()
    ..post('/upload', _handleFileUpload);

  final handler = Pipeline()
    .addMiddleware(logRequests())
    .addHandler(router.handler);

  await shelfListenAndServe(
    address: 'localhost',
    port: 8080,
    handler: handler,
  );
}

Future<Response> _handleFileUpload(Request request) async {
  final multipart = await request.readAsMultipart();
  final file = multipart.files.first.value;
  final savePath = './uploads/${file.filename}';

  await file.saveTo(File(savePath));

  return Response.ok('File uploaded successfully!');
}

确保你在运行后端服务之前创建了 uploads 目录。

总结

以上代码展示了如何在 Flutter 前端使用 dio 插件发送文件上传请求,并简要介绍了如何使用 Dart 后端(可选)来处理这些请求。请根据你的实际需求调整代码,例如后端 URL 和文件处理逻辑。

回到顶部