Flutter网络请求插件http_rest的使用

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

Flutter网络请求插件http_rest的使用

HTTP REST

HTTP REST 提供了所有必要的工具来简化和优化您的 HTTP 交互。它是一个基于流行的 Flutter 的 http 库的轻量级且灵活的网络库,并作为增强功能提供了一些额外的功能和功能,例如:

  • 中间件(拦截器)
  • 请求/响应体转换器
  • 请求/响应日志记录
  • 读/写进度跟踪
  • 带有进度的多部分请求

开始使用

创建一个 HttpRestClient 实例,然后运行 HttpRestRequest

import 'package:http/http.dart' as http;
import 'package:http_rest/http_rest.dart';

/// ...
final httpClient = HttpRestClient.builder(DefaultRequestExecutor(http.Client()))
    .addResponseConverter(JsonToMapResponseConverter()) // 添加响应转换器
    .addRequestConverter(MapToJsonRequestConverter()) // 添加请求转换器
    .addRequestMiddleware(RequestLogger()) // 添加请求中间件
    .addResponseMiddleware(ResponseLogger()) // 添加响应中间件
    .build();

// 这个请求将向图书馆添加一本书
final result = await httpClient.execute(HttpRestRequest(
    method: Methods.post,
    // 指定请求转换器类型
    requestConverterType: MapToJsonRequestConverter,
    // 指定响应转换器类型
    responseConverterType: JsonToMapResponseConverter,
    url: 'https://example.com/books',
    headers: {'Language': 'en'},
    body: {
      "id": 2,
      "bookName": "1984",
      "author": "George Orwell"
    }));

if (result.rowResponse.code == 201) {
  print(result.response); // 实例为 Map
}

同样的 httpClient 实例也可以用来执行其他 HTTP 请求。

// 这个请求会获取图书馆的书籍列表。
final result = await httpClient.execute(HttpRestRequest(
    method: Methods.get,
    responseConverterType: JsonToMapResponseConverter,
    url: 'https://example.com/books?count=10'));

中间件

HttpRestClient 使用中间件链来修改请求和响应。

以下是创建一个请求中间件以在每个 HttpRestRequest 中添加授权头的方法:

class AuthorizationMiddleware extends Middleware<RowRequest> {
  @override
  Future<RowRequest> onNext(
      RowRequest row, Middleware<RowRequest> nextMiddleware) async {
    row.request.headers['Authorization'] = 'YOUR AUTHORIZATION TOKEN';
    return await super.onNext(row, nextMiddleware);
  }
}

在构建 HttpRestClient 实例时添加它:

final httpClient = HttpRestClient.builder(
        DefaultRequestExecutor(http.Client()))
    .addResponseConverter(JsonToMapResponseConverter())
    .addRequestConverter(MapToJsonRequestConverter()) 
    .addRequestMiddleware(AuthorizationMiddleware()) // 添加
    .addRequestMiddleware(RequestLogger()) 
    .addResponseMiddleware(ResponseLogger())
    .build();

因此,Authorization 头将会被添加到由 httpClient 执行的所有请求中。

请注意,RequestLoggerResponseLogger 也是中间件。

可以在 HttpRestClient 中添加任意数量的请求和响应中间件,它们将以添加的顺序作为链调用。

转换器

转换器用于转换请求和响应体。库自带了一些默认的转换器:

  • MapToJsonRequestConverter 用于将请求的映射体转换为 JSON 字符串。
  • JsonToMapResponseConverter 用于将响应体字节转换为映射对象。
  • StringResponseConverter 用于将响应体字节转换为字符串。

每个 HttpRestRequest 可以指定请求和响应转换器类型,HttpRestClient 将使用指定的转换器来转换请求和响应体。

// 这个请求会获取图书馆的书籍列表。
final result = await httpClient.execute(HttpRestRequest(
    method: Methods.get,
    // 将请求体转换为 JSON
    responseConverterType: JsonToMapResponseConverter,
    url: 'https://example.com/books?count=10'));

以下是如何创建一个将接收到的体字节转换为映射实例的转换器:

import 'dart:convert';

class JsonToMapResponseConverter extends ResponseConverter {
  @override
  HttpRestResponse fromRow(RowResponse rowResponse) {
    dynamic jsonMap;
    final rowBody = rowResponse.bodyBytes;
    if (rowBody != null && rowBody.isNotEmpty) {
      final rowBodyUtf8 = utf8.decode(rowBody);
      jsonMap = json.decode(rowBodyUtf8);
    }
    return HttpRestResponse(rowResponse.request, rowResponse, jsonMap);
  }
}

注意,fromRow 方法接收 RowResponse 的实例并返回 HttpRestResponse 的实例。

  • RowResponse 是较低级别的响应模型,包含响应的 bodyBytes 以及其他内容,如响应码和响应头。
  • HttpRestResponseawait client.execute(HttpRestRequest(...)) 返回的实例,它包含原始的 HttpRestRequestRowResponse 和转换后的体 jsonMap

请求日志记录

RequestLoggerResponseLogger 用于在控制台中记录网络交互。

这里是如何在控制台中查看记录的请求的样子:

→ REQUEST →
POST: https://example.com/books
HEADERS:    Content-Type : application/json
            Authorization : eyJhbGciOi....
            Language : EN
            Version : 1.1.76
BODY:       {"id":2, "bookName":"1984", "author":"George Orwell"}

← RESPONSE ←
POST: https://example.com/books
CODE: 200
HEADERS:    connection : keep-alive
            date : Thu, 04 May 2023 19:02:10 GMT
            transfer-encoding : chunked
            vary : accept-encoding
            content-encoding : gzip
            strict-transport-security : max-age=15724800; includeSubDomains
            content-type : application/json

BODY:       {"message":"Success"}

使用 LogParts 枚举来控制可记录的部分:

enum LogParts {
  headers,
  body,
  url,
  code;

  static const all = {url, headers, code, body}; // 默认
}

默认情况下,请求和响应的所有部分都会被记录。这里是仅记录 URL 和头部的方法:

final httpClient = HttpRestClient.builder(
    DefaultRequestExecutor(http.Client()))
//...
    .addRequestMiddleware(RequestLogger(logParts: {LogParts.url, LogParts.headers})) // 中间件
    .addResponseMiddleware(ResponseLogger(logParts: {LogParts.url, LogParts.headers}))
    .build();

读/写进度跟踪

要跟踪任何请求的读取/写入进度,可以使用 HttpRestRequestwriteProgressListenerreadProgressListener 成员。

以下是如何从 GitHub 下载图像并跟踪下载进度的例子:

void downloadImage() => 
    httpClient.execute(HttpRestRequest(
      method: Methods.get,
      url: 'https://raw.githubusercontent.com/RobertApikyan/http_rest/main/doc/assets/intro.png',
      readProgressListener: (bytes, totalBytes) => print('download progress= ${bytes/totalBytes}'),
    ));

多部分请求

对于多部分请求,只需提供 MultipartRequestBodyHttpRestRequestbody 中。

以下是如何创建一个多部分请求以上传书籍并监控进度:

void uploadBook(MultipartFile multipartFile) => 
    httpClient.execute(HttpRestRequest(
      method: Methods.post,
      url: 'https://example.com/book',
      body: MultipartRequestBody(
        fields: {},
        files: [multipartFile],
        progressListener: (bytes, totalBytes) {
          // 监控进度
          final progress = bytes / totalBytes;
        },
      ),
    ));

请求执行器

RequestExecutor 负责实际执行 HTTP 请求并返回结果。这是一个抽象类,有一个单抽象方法 execute

abstract class RequestExecutor {
  /// 重写此方法并使用 [rowRequest] 参数中的参数实现 HTTP 调用。
  Future<RowResponse> execute(RowRequest rowRequest);
}

更多关于Flutter网络请求插件http_rest的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter网络请求插件http_rest的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用http_rest插件进行网络请求的示例代码。请注意,http_rest可能并不是一个非常流行或者广泛认可的插件名称,通常我们会使用http包来进行网络请求。不过,为了符合你的要求,我假设http_rest是一个类似于http的插件,并提供一个类似的API。

首先,确保你已经在pubspec.yaml文件中添加了http_rest依赖项(如果确实存在这个包的话,否则请替换为http):

dependencies:
  flutter:
    sdk: flutter
  http_rest: ^x.y.z  # 替换为实际的版本号

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

接下来,是一个使用http_rest(假设其API类似于http包)进行GET和POST请求的示例代码:

import 'package:flutter/material.dart';
import 'package:http_rest/http_rest.dart' as http_rest; // 假设包名为http_rest,并且有一个别名

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

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _responseText = '';

  void _makeGetRequest() async {
    try {
      var response = await http_rest.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
      setState(() {
        _responseText = response.body;
      });
    } catch (e) {
      setState(() {
        _responseText = 'Error: ${e.message}';
      });
    }
  }

  void _makePostRequest() async {
    try {
      var body = {
        'title': 'foo',
        'body': 'bar',
        'userId': 1,
      };
      var response = await http_rest.post(Uri.parse('https://jsonplaceholder.typicode.com/posts'),
          body: body);
      setState(() {
        _responseText = response.body;
      });
    } catch (e) {
      setState(() {
        _responseText = 'Error: ${e.message}';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Network Request Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text('Response:', style: TextStyle(fontSize: 18)),
            SizedBox(height: 10),
            Expanded(
              child: SingleChildScrollView(
                child: Text(_responseText, style: TextStyle(fontSize: 16)),
              ),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _makeGetRequest,
              child: Text('Make GET Request'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: _makePostRequest,
              child: Text('Make POST Request'),
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,它有两个按钮,一个用于发起GET请求,另一个用于发起POST请求。GET请求从jsonplaceholder.typicode.com获取一个帖子,而POST请求则向该网站提交一个新的帖子。

请注意,如果http_rest实际上不存在,或者其API与http包有很大不同,你可能需要查阅该插件的官方文档来正确调整代码。在实际开发中,http包是Flutter社区广泛使用的网络请求插件,其API非常直观和易用。

回到顶部