Rust实现带NTLM认证的Web POST请求及报错解决
报错修复方案
你遇到的method not found in HashMap<&str, String>报错来自三个逻辑错误:
HashMap本身未实现std::io::Readtrait,无法直接调用read()方法读取字节流- 你写的
post_field_size(map.len() as u64)逻辑错误,HashMap::len()返回的是键值对个数,不是POST请求体的字节长度 - 你没有明确请求体编码格式,和你最初reqwest版本的
json()逻辑对应,需要先将键值对序列化为JSON格式的字节数组,再传入curl处理。
首先在Cargo.toml中添加所需依赖:
[dependencies] curl = { version = "0.4", features = ["ntlm"] } serde_json = "1.0"
修复后的可运行代码如下:
use curl::easy::{Easy, Auth}; use serde_json::json; use std::io::{Cursor, Read}; // 序列化为和reqwest版本一致的JSON请求体 let req_body = json!({ "test": "test" }).to_string(); // 用标准库的Cursor包裹字节切片,Cursor默认实现Read trait,无需自行实现读逻辑 let mut body_reader = Cursor::new(req_body.as_bytes()); let mut easy = Easy::new(); easy.url(&format!("{}/create", URL)).unwrap(); easy.post(true).unwrap(); // 正确设置请求体字节长度 easy.post_field_size(req_body.len() as u64).unwrap(); // 配置NTLM认证:域账号格式为`域名\用户名`,本地账号直接填用户名即可 easy.username("YOUR_DOMAIN\\your_username").unwrap(); easy.password("your_password").unwrap(); // 必须显式开启NTLM认证,否则不会触发NTLM握手流程 easy.http_auth(Auth::new().ntlm(true)).unwrap(); // 匹配JSON请求的Content-Type头 easy.http_headers({ let mut headers = curl::easy::List::new(); headers.append("Content-Type: application/json").unwrap(); headers }).unwrap(); let mut transfer = easy.transfer(); transfer.read_function(move |buf| { Ok(body_reader.read(buf).unwrap_or(0)) }).unwrap(); transfer.perform().unwrap();
如果你需要发送表单格式的请求体,只需要把JSON序列化替换为serde_urlencoded序列化字符串即可,读取逻辑完全一致。
NTLM方案选型说明
开启ntlm特性的curl crate是生产环境可用的成熟方案:该crate是对原生libcurl的Rust绑定,libcurl的NTLM实现(含NTLMv2、域认证场景)经过十余年的生产验证,兼容性和稳定性表现最好。
如果你不想引入依赖C库的绑定、降低交叉编译成本,也可以选择纯Rust实现的方案,不需要放弃你最初使用的reqwest栈:
直接给reqwest集成NTLM中间件即可,依赖配置如下:
[dependencies] reqwest = { version = "0.11", features = ["json"] } reqwest-ntlm = "0.3" serde_json = "1.0"
对应代码和你最初的写法差异极小:
use reqwest::Client; use reqwest_ntlm::NtlmAuth; use std::collections::HashMap; let client = Client::builder() .with_ntlm_auth("YOUR_DOMAIN\\your_username", "your_password") .build()?; let mut map = HashMap::new(); map.insert("test", "test"); let res = client.post(format!("{}/create", URL)) .json(&map) .send() .await?;
两个方案的选择逻辑:
- 部署环境固定、需要兼容旧版NTLM服务、追求最高稳定性,选curl crate方案
- 需要纯Rust依赖、项目已在使用reqwest、追求代码简洁,选reqwest+NTLM中间件方案
内容的提问来源于stack exchange,提问作者Doomed
相关产品推荐
相关产品推荐

