Rust HTTP请求处理库http-serde-ext的使用:增强serde的HTTP序列化与反序列化功能
Rust HTTP请求处理库http-serde-ext的使用:增强serde的HTTP序列化与反序列化功能
简介
http-serde-ext提供了对http
crate中类型的serde序列化和反序列化支持,包括:
Response
Request
HeaderMap
StatusCode
Uri
Method
HeaderName
HeaderValue
uri::Authority
uri::Scheme
uri::PathAndQuery
Version
- 通用的
HeaderMap<T>
(其中T不是HeaderValue
)
还支持上述类型包装在以下std
容器类型中:
Option
Result
(Ok位置)Vec
VecDeque
LinkedList
HashMap
(作为Key,除了HeaderMap
、Request
和Response
;作为Value支持所有类型)BTreeMap
(作为Key仅支持HeaderValue
、StatusCode
和Version
;作为Value支持所有类型)HashSet
(除了HeaderMap
、Request
和Response
)BTreeSet
(仅支持HeaderValue
、StatusCode
和Version
)
安装
在项目目录中运行以下Cargo命令:
cargo add http-serde-ext
或者在Cargo.toml中添加以下行:
http-serde-ext = "1.0.2"
使用示例
这个库旨在与serde的derive
功能一起使用。字段应使用适当的#[serde(with = "...")]
注解。以下是完整示例:
use std::collections::*;
use http::*;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct MyStruct {
#[serde(with = "http_serde_ext::response")]
base: Response<Vec<u8>>,
#[serde(with = "http_serde_ext::request::option", default)]
option: Option<Request<String>>,
#[serde(with = "http_serde_ext::method::vec")]
vec: Vec<Method>,
#[serde(with = "http_serde_ext::uri::vec_deque")]
vec_deque: VecDeque<Uri>,
#[serde(with = "http_serde_ext::header_map::linked_list")]
linked_list: LinkedList<HeaderMap>,
#[serde(with = "http_serde_ext::header_map_generic::hash_map")]
hash_map: HashMap<String, HeaderMap<String>>,
#[serde(with = "http_serde_ext::status_code::btree_map_key")]
btree_map: BTreeMap<StatusCode, i32>,
#[serde(with = "http_serde_ext::authority::hash_set")]
hash_set: HashSet<uri::Authority>,
}
这个库也可以用于手动序列化/反序列化类型,例如使用serde_json
时:
let uri = http::Uri::default();
let serialized = http_serde_ext::uri::serialize(&uri, serde_json::value::Serializer).unwrap();
let deserialized = http_serde_ext::uri::deserialize(serialized).unwrap();
assert_eq!(uri, deserialized);
let mut responses: Vec<http::Response<()>> = vec![http::Response::default()];
let serialized =
http_serde_ext::response::vec::serialize(&responses, serde_json::value::Serializer)
.unwrap();
let mut deserialized: Vec<http::Response<()>> =
http_serde_ext::response::vec::deserialize(serialized).unwrap();
let original = responses.remove(0).into_parts();
let deserialized = deserialized.remove(0).into_parts();
assert_eq!(original.0.status, deserialized.0.status);
assert_eq!(original.0.version, deserialized.0.version);
assert_eq(original.0.headers, deserialized.0.headers);
assert_eq!(original.1, deserialized.1);
完整示例代码
use std::collections::{BTreeMap, HashMap, HashSet, LinkedList, VecDeque};
use http::{HeaderMap, Method, Request, Response, StatusCode, Uri};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct ApiResponse {
#[serde(with = "http_serde_ext::response")]
response: Response<String>,
#[serde(with = "http_serde_ext::status_code::btree_map_key")]
status_codes: BTreeMap<StatusCode, &'static str>,
#[serde(with = "http_serde_ext::uri::vec_deque")]
endpoints: VecDeque<Uri>,
}
fn main() {
// 创建一个响应示例
let response = Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/json")
.body("{\"message\":\"Hello, World!\"}".to_string())
.unwrap();
// 创建状态码映射
let mut status_codes = BTreeMap::new();
status_codes.insert(StatusCode::OK, "OK");
status_codes.insert(StatusCode::NOT_FOUND, "Not Found");
// 创建端点列表
let mut endpoints = VecDeque::new();
endpoints.push_back("/api/v1/users".parse().unwrap());
endpoints.push_back("/api/v1/products".parse().unwrap());
// 构建我们的结构体
let api_response = ApiResponse {
response,
status_codes,
endpoints,
};
// 序列化为JSON
let json = serde_json::to_string(&api_response).unwrap();
println!("Serialized JSON:\n{}", json);
// 反序列化
let deserialized: ApiResponse = serde_json::from_str(&json).unwrap();
println!("Deserialized response status: {}", deserialized.response.status());
}
完整示例demo
下面是一个更完整的示例,展示如何使用http-serde-ext处理HTTP请求和响应:
use std::collections::{BTreeMap, HashMap};
use http::{header, HeaderMap, Method, Request, Response, StatusCode, Uri};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct ApiRequest {
#[serde(with = "http_serde_ext::request")]
request: Request<String>,
#[serde(with = "http_serde_ext::header_map::hash_map")]
custom_headers: HashMap<String, HeaderMap<String>>,
}
#[derive(Debug, Serialize, Deserialize)]
struct ApiResponse {
#[serde(with = "http_serde_ext::response")]
response: Response<String>,
#[serde(with = "http_serde_ext::status_code::btree_map_key")]
status_mapping: BTreeMap<StatusCode, String>,
}
fn main() {
// 创建请求示例
let request = Request::builder()
.method(Method::POST)
.uri("/api/v1/data")
.header("Authorization", "Bearer token")
.body("{\"data\":\"test\"}".to_string())
.unwrap();
// 创建自定义头映射
let mut custom_headers = HashMap::new();
let mut headers1 = HeaderMap::new();
headers1.insert("X-Custom-1", "Value1".parse().unwrap());
custom_headers.insert("req1".to_string(), headers1);
// 构建请求结构体
let api_request = ApiRequest {
request,
custom_headers,
};
// 序列化请求
let request_json = serde_json::to_string(&api_request).unwrap();
println!("Serialized Request:\n{}", request_json);
// 创建响应示例
let response = Response::builder()
.status(StatusCode::CREATED)
.header("Content-Type", "application/json")
.header("X-Rate-Limit", "100")
.body("{\"id\":123}".to_string())
.unwrap();
// 创建状态码映射
let mut status_mapping = BTreeMap::new();
status_mapping.insert(StatusCode::OK, "Success".to_string());
status_mapping.insert(StatusCode::CREATED, "Created".to_string());
// 构建响应结构体
let api_response = ApiResponse {
response,
status_mapping,
};
// 序列化响应
let response_json = serde_json::to_string(&api_response).unwrap();
println!("Serialized Response:\n{}", response_json);
// 反序列化请求
let deserialized_request: ApiRequest = serde_json::from_str(&request_json).unwrap();
println!(
"Deserialized Request Method: {}",
deserialized_request.request.method()
);
// 反序列化响应
let deserialized_response: ApiResponse = serde_json::from_str(&response_json).unwrap();
println!(
"Deserialized Response Status: {}",
deserialized_response.response.status()
);
}
致谢
这个crate很大程度上受到Kornel的http-serde
的启发。
1 回复
Rust HTTP请求处理库http-serde-ext使用指南
http-serde-ext
是一个增强Rust中HTTP请求和响应处理的库,它扩展了serde
的功能,使其能更好地处理HTTP相关的序列化和反序列化操作。
主要特性
- 增强HTTP头部的序列化/反序列化
- 改进HTTP查询参数的序列化/反序列化
- 简化HTTP请求体和响应体的处理
- 与主流HTTP框架(如actix-web, warp等)无缝集成
安装
在Cargo.toml
中添加依赖:
[dependencies]
http-serde-ext = "0.1"
serde = { version = "1.0", features = ["derive"] }
基本使用方法
1. 处理HTTP头部
use http::header::HeaderMap;
use serde::{Deserialize, Serialize};
use http_serde_ext::header::from_headers;
#[derive(Debug, Deserialize)]
struct MyHeaders {
#[serde(rename = "x-request-id")]
request_id: String,
#[serde(rename = "content-type")]
content_type: Option<String>,
}
fn process_headers(headers: &HeaderMap) {
let my_headers: MyHeaders = from_headers(headers).unwrap();
println!("Request ID: {}", my_headers.request_id);
}
2. 处理查询参数
use serde::{Deserialize, Serialize};
use http_serde_ext::query::from_query;
#[derive(Debug, Deserialize)]
struct Pagination {
page: u32,
per_page: u32,
sort: Option<String>,
}
fn process_query(query: &str) {
let pagination: Pagination = from_query(query).unwrap();
println!("Page: {}, Per page: {}", pagination.page, pagination.per_page);
}
3. 处理请求体和响应体
use serde::{Deserialize, Serialize};
use http_serde_ext::body::{from_body, to_body};
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u64,
name: String,
email: String,
}
// 反序列化请求体
fn process_request(body: &[u8]) {
let user: User = from_body(body).unwrap();
println!("User: {:?}", user);
}
// 序列化响应体
fn create_response() -> Vec<u8> {
let user = User {
id: 1,
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
};
to_body(&user).unwrap()
}
与actix-web集成示例
use actix_web::{get, post, web, App, HttpServer, HttpResponse};
use serde::{Deserialize, Serialize};
use http_serde_ext::{header::from_headers, query::from_query, body::{from_body, to_body}};
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u64,
name: String,
}
#[get("/users")]
async fn get_users(headers: web::HeaderMap, query: web::Query<String>) -> HttpResponse {
// 处理头部
let my_headers: MyHeaders = from_headers(&headers).unwrap();
// 处理查询参数
let pagination: Pagination = from_query(&query).unwrap();
// 返回响应
let users = vec![User { id: 1, name: "Alice".to_string() }];
HttpResponse::Ok()
.body(to_body(&users).unwrap())
}
#[post("/users")]
async fn create_user(body: web::Bytes) -> HttpResponse {
// 处理请求体
let user: User = from_body(&body).unwrap();
HttpResponse::Created()
.body(to_body(&user).unwrap())
}
高级用法
自定义序列化/反序列化
use serde::{Deserialize, Serialize, de::Deserializer, ser::Serializer};
use http_serde_ext::header::{serialize_header, deserialize_header};
#[derive(Debug)]
struct CustomType(String);
impl Serialize for CustomType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_header(&self.0, serializer)
}
}
impl<'de> Deserialize<'de> for CustomType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = deserialize_header(deserializer)?;
Ok(CustomType(s))
}
}
注意事项
- 错误处理:所有操作都可能失败,请妥善处理
Result
- 性能考虑:对于大型请求体,考虑使用流式处理
- 安全性:始终验证和清理输入数据
http-serde-ext
通过扩展serde
的功能,大大简化了Rust中HTTP请求和响应的处理流程,特别是在需要与多种HTTP组件交互的复杂应用中。
完整示例Demo
下面是一个完整的actix-web应用示例,展示了如何使用http-serde-ext处理HTTP请求和响应:
use actix_web::{web, App, HttpServer, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
use http_serde_ext::{header::from_headers, query::from_query, body::{from_body, to_body}};
// 定义数据结构
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u64,
name: String,
email: String,
}
#[derive(Debug, Deserialize)]
struct MyHeaders {
#[serde(rename = "x-request-id")]
request_id: String,
}
#[derive(Debug, Deserialize)]
struct Pagination {
page: u32,
per_page: u32,
}
// 处理用户列表请求
async fn list_users(
headers: web::HeaderMap,
query: web::Query<String>
) -> impl Responder {
// 解析头部
let headers: MyHeaders = from_headers(&headers).unwrap();
println!("Request ID: {}", headers.request_id);
// 解析查询参数
let pagination: Pagination = from_query(&query).unwrap();
println!("Page: {}, Per page: {}", pagination.page, pagination.per_page);
// 创建响应数据
let users = vec![
User {
id: 1,
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
},
User {
id: 2,
name: "Bob".to_string(),
email: "bob@example.com".to_string(),
}
];
// 返回响应
HttpResponse::Ok()
.body(to_body(&users).unwrap())
}
// 处理创建用户请求
async fn create_user(body: web::Bytes) -> impl Responder {
// 解析请求体
let user: User = from_body(&body).unwrap();
println!("Received user: {:?}", user);
// 返回响应
HttpResponse::Created()
.body(to_body(&user).unwrap())
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/users", web::get().to(list_users))
.route("/users", web::post().to(create_user))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
这个完整示例展示了:
- 使用
from_headers
处理HTTP头部 - 使用
from_query
处理查询参数 - 使用
from_body
处理请求体 - 使用
to_body
生成响应体 - 与actix-web框架的集成
要运行这个示例,请确保在Cargo.toml中添加了必要的依赖:
[dependencies]
actix-web = "4.0"
http-serde-ext = "0.1"
serde = { version = "1.0", features = ["derive"] }