编程 Rust API 服务器:发送和接收字节数据

2024-11-18 18:17:46 +0800 CST views 473

Rust API 服务器:发送和接收字节数据

在现代网络应用中,处理二进制数据(例如文件上传和下载)是不可避免的任务。本文将深入探讨如何使用 Rust 构建强大的 API 服务器,以处理发送和接收字节数据的各种场景。我们将使用 axum 框架,这是一个非常适合路由请求和声明式解析请求的 Web 应用框架。

准备工作

首先,在 Cargo.toml 文件中添加必要的依赖项:

[dependencies]
tokio = { version = "1", features = ["macros"] }
lambda_http = "0.13.0"
axum = { version = "0.7.5", features = ["multipart"] }
tower-http = { version = "0.5.2", features = ["limit"] }
regex = "1.10.6"
urlencoding = "2.1.3"

这些依赖项包括 axum(用于构建 Web 应用程序)、tokio(用于异步运行时)、tower-http(用于设置请求体大小限制)、regex(用于解析文件名)、urlencoding(用于处理文件名编码)以及 lambda_http(用于在 AWS Lambda 上部署,作为可选项)。

接收二进制数据

直接接收字节数据

当直接接收请求体中的字节数据时,我们需要在处理函数中完成以下步骤:

  • Content-Disposition 头部信息中提取 file_name
  • Bytes 类型转换为 Vec<u8> 类型,以便后续处理,例如保存文件。
use axum::{
    http::HeaderMap,
    Json,
    extract::Bytes,
    response::{IntoResponse, Response},
};
use serde_json::{json, Value};
use regex::Regex;
use urlencoding::decode;

async fn post_bytes(headers: HeaderMap, bytes: Bytes) -> Json<Value> {
    let Some(content_disposition) = headers.get("content-disposition") else {
        return Json(json!({
            "message": "Content-Disposition header not available"
        }));
    };

    let Ok(content_disposition_string) = content_disposition.to_str() else {
        return Json(json!({
            "message": "Invalid Content-Disposition header"
        }));
    };

    let Ok(re) = Regex::new(r#"filename\*?=utf-8''(?<name>.+)"#) else {
        return Json(json!({
            "message": "Failed to create regex"
        }));
    };

    let Some(captures) = re.captures(content_disposition_string) else {
        return Json(json!({
            "message": "File name not found"
        }));
    };

    let file_name = decode(&captures["name"]).expect("UTF-8").to_string();
    let data: Vec<u8> = bytes.to_vec();

    Json(json!({
        "file_name": file_name,
        "data_length": data.len()
    }))
}

这段代码首先尝试从请求头中获取 Content-Disposition 字段,然后使用正则表达式提取文件名。最后,将字节数据收集到 Vec<u8> 中,并返回包含文件名和数据长度的 JSON 响应。

处理 Multipart/form-data 数据

对于 Multipart/form-data 类型的请求,我们需要使用 axum::extract::Multipart 来处理。

use axum::extract::Multipart;

async fn post_bytes_multiparts(mut multipart: Multipart) -> Json<Value> {
    while let Some(field) = multipart.next_field().await.unwrap() {
        let name = field.name().unwrap().to_string();
        let file_name = field.file_name().unwrap().to_string();
        let content_type = field.content_type().unwrap().to_string();
        let data = field.bytes().await.unwrap();

        if name == "file" {
            return Json(json!({
                "file_name": file_name,
                "content_type": content_type,
                "data_length": data.len()
            }));
        }
    }

    Json(json!({
        "message": "File field is missing in the form."
    }))
}

这段代码使用 Multipart 提取器迭代表单中的每个字段,并检查字段名称是否为 "file"。如果是,则提取文件名、内容类型和数据,并返回 JSON 响应。

设置请求体大小限制

为了防止恶意请求导致服务器资源耗尽,我们需要设置请求体大小限制。默认情况下,axum 会将请求体大小限制为 2MB。

use axum::Router;
use tower::ServiceBuilder;
use tower_http::limit::RequestBodyLimitLayer;

let app = Router::new()
    // 设置请求体大小限制为 10GB
    .layer(
        ServiceBuilder::new()
            .layer(RequestBodyLimitLayer::new(10 * 1024 * 1024 * 1024))
    );

这段代码使用 RequestBodyLimitLayer 设置新的请求体大小限制为 10GB。

发送二进制数据

与接收二进制数据不同,发送二进制数据时,我们需要确保响应头中的 Content-TypeContent-Disposition 设置正确。

use axum::http::{HeaderMap, HeaderValue, StatusCode};
use axum::response::Response;
use axum::extract::Bytes;
use regex::Regex;
use urlencoding::encode;

async fn echo_bytes(headers: HeaderMap, bytes: Bytes) -> Response {
    let content_type = headers.get("content-type").unwrap();
    let content_disposition = headers.get("content-disposition").unwrap().to_str().unwrap();
    let re = Regex::new(r#"filename\*?=utf-8''(?<name>.+)"#).unwrap();
    let captures = re.captures(content_disposition).unwrap();
    let file_name = decode(&captures["name"]).unwrap().to_string();
    let file_name_encode = encode(&file_name).to_string();

    let mut headers = HeaderMap::new();
    headers.insert("content-type", content_type.to_owned());
    headers.insert("content-length", HeaderValue::from(bytes.len()));
    headers.insert("content-disposition", HeaderValue::from_str(&format!("attachment; filename*=utf-8''{}", file_name_encode)).unwrap());

    (headers, bytes.to_vec()).into_response()
}

这段代码从请求头中获取 Content-TypeContent-Disposition 字段,提取文件名后,构建新的响应头,并将字节数据作为响应体返回。

总结

本文详细介绍了如何使用 Rust 构建 API 服务器来处理发送和接收字节数据。我们学习了如何使用 axum 框架处理不同类型的请求,如何设置请求体大小限制,以及如何正确设置响应头以发送二进制数据。

复制全文 生成海报 编程 网络应用 Rust Web开发 API

推荐文章

CentOS 镜像源配置
2024-11-18 11:28:06 +0800 CST
12个非常有用的JavaScript技巧
2024-11-19 05:36:14 +0800 CST
Vue3中哪些API被废弃了?
2024-11-17 04:17:22 +0800 CST
css模拟了MacBook的外观
2024-11-18 14:07:40 +0800 CST
Requests库详细介绍
2024-11-18 05:53:37 +0800 CST
Vue3中如何处理组件间的动画?
2024-11-17 04:54:49 +0800 CST
Rust开发笔记 | Rust的交互式Shell
2024-11-18 19:55:44 +0800 CST
如何实现生产环境代码加密
2024-11-18 14:19:35 +0800 CST
Vue3中的自定义指令有哪些变化?
2024-11-18 07:48:06 +0800 CST
Elasticsearch 聚合和分析
2024-11-19 06:44:08 +0800 CST
快手小程序商城系统
2024-11-25 13:39:46 +0800 CST
Node.js中接入微信支付
2024-11-19 06:28:31 +0800 CST
H5端向App端通信(Uniapp 必会)
2025-02-20 10:32:26 +0800 CST
对多个数组或多维数组进行排序
2024-11-17 05:10:28 +0800 CST
浅谈CSRF攻击
2024-11-18 09:45:14 +0800 CST
程序员茄子在线接单