Rust HTTP归档库har的使用:高效解析与生成HTTP请求/响应数据格式
Rust HTTP归档库har的使用:高效解析与生成HTTP请求/响应数据格式
HTTP归档格式(HAR)序列化与反序列化库,使用Rust编写。
安装
在您的Cargo.toml
文件中添加以下内容:
[dependencies]
har = "0.8"
使用
最简单的示例:
use har::from_path;
fn main() {
match har::from_path("path/to/file.har") {
Ok(spec) => println!("spec: {:?}", spec),
Err(err) => println!("error: {}", err)
}
}
完整示例代码
基于提供的示例,以下是一个更完整的HAR文件解析和生成示例:
use har::{Har, from_path, to_string};
use std::fs::File;
use std::io::Read;
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 示例1: 从文件路径解析HAR文件
let har_path = "example.har";
match from_path(har_path) {
Ok(har) => {
println!("成功解析HAR文件:");
println!("版本: {}", har.log.version);
println!("创建者: {}", har.log.creator.name);
println!("条目数量: {}", har.log.entries.len());
// 打印所有请求的URL
for (i, entry) in har.log.entries.iter().enumerate() {
println!("条目 {}: {}", i + 1, entry.request.url);
}
}
Err(err) => println!("解析错误: {}", err),
}
// 示例2: 从字符串内容解析HAR
let har_content = r#"
{
"log": {
"version": "1.2",
"creator": {
"name": "Example Creator",
"version": "1.0"
},
"entries": [
{
"request": {
"method": "GET",
"url": "https://example.com",
"httpVersion": "HTTP/1.1",
"headers": [],
"queryString": [],
"cookies": [],
"headersSize": 150,
"bodySize": 0
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"headers": [],
"cookies": [],
"content": {
"size": 1270,
"mimeType": "text/html"
},
"redirectURL": "",
"headersSize": 150,
"bodySize": 1120
},
"startedDateTime": "2024-01-01T00:00:00.000Z",
"time": 50,
"cache": {},
"timings": {
"send": 10,
"wait": 30,
"receive": 10
}
}
]
}
}"#;
// 解析字符串内容
let har: Har = serde_json::from_str(har_content)?;
println!("\n从字符串解析的HAR:");
println!("版本: {}", har.log.version);
// 示例3: 生成HAR字符串
let generated_har = to_string(&har)?;
println!("\n生成的HAR字符串:");
println!("{}", generated_har);
Ok(())
}
// 示例4: 创建新的HAR条目
fn create_har_example() -> Har {
Har {
log: har::Log {
version: "1.2".to_string(),
creator: har::Creator {
name: "Rust HAR Library".to_string(),
version: "0.8.0".to_string(),
comment: None,
},
browser: None,
pages: None,
entries: vec![],
comment: None,
},
}
}
贡献
该项目遵循语义化版本控制、约定式提交和使用mandrean/semantic-rs进行语义发布。
注意
灵感来源于softprops/openapi。
1 回复
Rust HTTP归档库har的使用:高效解析与生成HTTP请求/响应数据格式
概述
har
是一个用于解析和生成HTTP归档格式(HTTP Archive format)的Rust库。该格式用于记录HTTP请求和响应的详细信息,常用于性能分析、调试和测试场景。
安装方法
在Cargo.toml中添加依赖:
[dependencies]
har = "0.1"
核心功能
1. 解析HAR文件
use har::Har;
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = File::open("example.har")?;
let har: Har = serde_json::from_reader(file)?;
println!("HAR版本: {}", har.version);
println!("包含{}个请求", har.log.entries.len());
Ok(())
}
2. 生成HAR文件
use har::{Har, Log, Entry, Request, Response};
use std::time::SystemTime;
fn create_sample_har() -> Har {
Har {
version: "1.2".to_string(),
log: Log {
version: "1.2".to_string(),
creator: har::Creator {
name: "my-app".to_string(),
version: "1.0".to_string(),
},
entries: vec![Entry {
started_date_time: SystemTime::now(),
time: 100.0,
request: Request {
method: "GET".to_string(),
url: "https://example.com/api/data".to_string(),
headers: vec![],
query_string: vec![],
post_data: None,
headers_size: -1,
body_size: -1,
},
response: Response {
status: 200,
status_text: "OK".to_string(),
headers: vec![],
content: har::Content {
size: 1024,
mime_type: "application/json".to_string(),
text: Some(r#"{"data": "example"}"#.to_string()),
},
redirect_url: "".to_string(),
headers_size: -1,
body_size: -1,
},
cache: har::Cache::default(),
timings: har::Timings {
blocked: -1.0,
dns: -1.0,
connect: -1.0,
send: 10.0,
wait: 50.0,
receive: 40.0,
ssl: -1.0,
},
server_ip_address: None,
connection: None,
comment: None,
}],
},
}
}
3. 处理请求和响应数据
use har::Har;
fn analyze_har(har: &Har) {
for (i, entry) in har.log.entries.iter().enumerate() {
println!("请求 {}: {}", i + 1, entry.request.url);
println!("方法: {}", entry.request.method);
println!("状态码: {}", entry.response.status);
println!("响应时间: {}ms", entry.time);
println!("---");
}
}
4. 过滤和搜索条目
use har::Har;
fn find_requests_by_status(har: &Har, status_code: u16) -> Vec<&Entry> {
har.log.entries
.iter()
.filter(|entry| entry.response.status == status_code)
.collect()
}
fn find_requests_by_url(har: &Har, url_pattern: &str) -> Vec<&Entry> {
har.log.entries
.iter()
.filter(|entry| entry.request.url.contains(url_pattern))
.collect()
}
完整示例:读取和分析HAR文件
use har::Har;
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 读取HAR文件
let file = File::open("network_logs.har")?;
let har: Har = serde_json::from_reader(file)?;
// 分析性能数据
let total_time: f64 = har.log.entries.iter().map(|e| e.time).sum();
let avg_time = total_time / har.log.entries.len() as f64;
println!("总请求数: {}", har.log.entries.len());
println!("总耗时: {:.2}ms", total_time);
println!("平均请求时间: {:.2}ms", avg_time);
// 统计状态码分布
let mut status_counts = std::collections::HashMap::new();
for entry in &har.log.entries {
*status_counts.entry(entry.response.status).or_insert(0) += 1;
}
println!("\n状态码分布:");
for (status, count) in status_counts {
println!("{}: {} 次请求", status, count);
}
Ok(())
}
最佳实践
- 错误处理:始终处理可能的解析错误
- 内存管理:对于大型HAR文件,考虑流式处理
- 数据验证:验证HAR文件的结构完整性
- 性能优化:在处理大量数据时使用适当的缓存策略
注意事项
- HAR文件可能包含敏感信息,处理时需注意数据安全
- 确保HAR文件符合规范格式,避免解析错误
- 考虑使用异步处理来提高大文件的处理性能
这个库为处理HTTP归档数据提供了强大而灵活的工具,特别适合网络性能分析和调试场景。
完整示例Demo
use har::{Har, Log, Entry, Request, Response, Creator, Content, Cache, Timings};
use std::fs::File;
use std::io::Write;
use std::time::SystemTime;
use std::collections::HashMap;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 示例1: 创建并写入HAR文件
println!("创建示例HAR文件...");
let har = create_sample_har();
// 将HAR对象序列化为JSON并写入文件
let mut file = File::create("sample.har")?;
let json = serde_json::to_string_pretty(&har)?;
file.write_all(json.as_bytes())?;
println!("HAR文件已创建: sample.har");
// 示例2: 读取并解析HAR文件
println!("\n读取并解析HAR文件...");
let file = File::open("sample.har")?;
let parsed_har: Har = serde_json::from_reader(file)?;
// 显示基本信息
println!("HAR版本: {}", parsed_har.version);
println!("创建者: {} {}", parsed_har.log.creator.name, parsed_har.log.creator.version);
println!("包含{}个请求条目", parsed_har.log.entries.len());
// 示例3: 分析HAR数据
println!("\n分析HAR数据...");
analyze_har(&parsed_har);
// 示例4: 过滤请求
println!("\n过滤状态码为200的请求...");
let successful_requests = find_requests_by_status(&parsed_har, 200);
println!("找到{}个成功的请求", successful_requests.len());
// 示例5: 性能统计
println!("\n性能统计:");
let total_time: f64 = parsed_har.log.entries.iter().map(|e| e.time).sum();
let avg_time = total_time / parsed_har.log.entries.len() as f64;
println!("总请求数: {}", parsed_har.log.entries.len());
println!("总耗时: {:.2}ms", total_time);
println!("平均请求时间: {:.2}ms", avg_time);
// 统计状态码分布
let mut status_counts = HashMap::new();
for entry in &parsed_har.log.entries {
*status_counts.entry(entry.response.status).or_insert(0) += 1;
}
println!("\n状态码分布:");
for (status, count) in status_counts {
println!("{}: {} 次请求", status, count);
}
Ok(())
}
// 创建示例HAR文件
fn create_sample_har() -> Har {
Har {
version: "1.2".to_string(),
log: Log {
version: "1.2".to_string(),
creator: Creator {
name: "har-demo-app".to_string(),
version: "1.0".to_string(),
},
entries: vec![
// 第一个请求条目
Entry {
started_date_time: SystemTime::now(),
time: 150.0,
request: Request {
method: "GET".to_string(),
url: "https://api.example.com/users".to_string(),
headers: vec![],
query_string: vec![],
post_data: None,
headers_size: -1,
body_size: -1,
},
response: Response {
status: 200,
status_text: "OK".to_string(),
headers: vec![],
content: Content {
size: 2048,
mime_type: "application/json".to_string(),
text: Some(r#"{"users": ["user1", "user2", "user3"]}"#.to_string()),
},
redirect_url: "".to_string(),
headers_size: -1,
body_size: -1,
},
cache: Cache::default(),
timings: Timings {
blocked: -1.0,
dns: 10.0,
connect: 20.0,
send: 5.0,
wait: 80.0,
receive: 35.0,
ssl: -1.0,
},
server_ip_address: None,
connection: None,
comment: None,
},
// 第二个请求条目
Entry {
started_date_time: SystemTime::now(),
time: 80.0,
request: Request {
method: "POST".to_string(),
url: "https://api.example.com/login".to_string(),
headers: vec![],
query_string: vec![],
post_data: None,
headers_size: -1,
body_size: -1,
},
response: Response {
status: 401,
status_text: "Unauthorized".to_string(),
headers: vec![],
content: Content {
size: 512,
mime_type: "application/json".to_string(),
text: Some(r#"{"error": "Invalid credentials"}"#.to_string()),
},
redirect_url: "".to_string(),
headers_size: -1,
body_size: -1,
},
cache: Cache::default(),
timings: Timings {
blocked: -1.0,
dns: 5.0,
connect: 15.0,
send: 3.0,
wait: 40.0,
receive: 17.0,
ssl: -1.0,
},
server_ip_address: None,
connection: None,
comment: None,
}
],
},
}
}
// 分析HAR文件内容
fn analyze_har(har: &Har) {
for (i, entry) in har.log.entries.iter().enumerate() {
println!("条目 {}:", i + 1);
println!(" URL: {}", entry.request.url);
println!(" 方法: {}", entry.request.method);
println!(" 状态码: {}", entry.response.status);
println!(" 响应大小: {} bytes", entry.response.content.size);
println!(" 总时间: {}ms", entry.time);
println!(" 时间分解 - DNS: {}ms, 连接: {}ms, 发送: {}ms, 等待: {}ms, 接收: {}ms",
entry.timings.dns, entry.timings.connect,
entry.timings.send, entry.timings.wait, entry.timings.receive);
println!("---");
}
}
// 根据状态码过滤请求
fn find_requests_by_status(har: &Har, status_code: u16) -> Vec<&Entry> {
har.log.entries
.iter()
.filter(|entry| entry.response.status == status_code)
.collect()
}
// 根据URL模式过滤请求
fn find_requests_by_url(har: &Har, url_pattern: &str) -> Vec<&Entry> {
har.log.entries
.iter()
.filter(|entry| entry.request.url.contains(url_pattern))
.collect()
}