Flutter文件上传插件shelf_multipart的使用
Flutter文件上传插件shelf_multipart的使用
shelf_multipart
插件用于解析 multipart
和 multipart/form-data
请求,为 shelf handlers 提供了处理多部分请求的能力。本文将详细介绍如何使用该插件进行文件上传,并提供完整的示例代码。
处理多部分请求
多部分请求由 MultipartRequest
扩展类型表示。要检查一个请求是否是多部分请求,可以使用 MultipartRequest.of
或 Request.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');
}
}
如何测试
- 启动服务器:运行上述代码,启动本地服务器。
- 使用 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
更多关于Flutter文件上传插件shelf_multipart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个使用 shelf_multipart
插件在 Flutter 中实现文件上传的示例代码。shelf_multipart
插件通常用于 Dart 后端服务来处理文件上传,但这里我们将关注如何在 Flutter 前端构建文件上传功能。实际上,Flutter 前端通常不会直接使用 shelf_multipart
,而是与后端服务进行通信来上传文件。
假设你有一个 Dart 后端服务使用 shelf
和 shelf_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 后端示例,使用 shelf
和 shelf_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 和文件处理逻辑。