Rust网络编程实战:全面掌握reqwest库的高级用法

一、开篇导引

1.1 对比Python Requests解释为何reqwest是Rust生态的标杆HTTP客户端

在Python生态中,Requests 库以其简洁易用的API成为了HTTP客户端的首选。它使得开发者能够轻松地发送各种HTTP请求,处理响应,而无需过多关注底层细节。然而,Python作为一种解释型语言,在性能和并发处理方面存在一定的局限性。

Rust的 reqwest 库则在性能、安全性和并发处理上展现出了强大的优势。reqwest 是基于Rust的异步运行时构建的,它充分利用了Rust的所有权系统和类型系统,能够高效地处理大量并发请求,同时保证内存安全。与Python的 Requests 相比,reqwest 在处理高并发场景时,性能提升显著。例如,在处理大量的API请求时,reqwest 能够在更短的时间内完成更多的请求,并且占用更少的系统资源。

1.2 适用场景分析:何时选择reqwest而非hyper/ureq等其他库

库名适用场景原因
reqwest高并发的Web服务、API客户端、爬虫开发提供了简洁的API,同时支持异步和同步模式,易于使用和扩展。
hyper底层HTTP服务开发、自定义HTTP协议实现是一个底层的HTTP库,提供了更细粒度的控制,但API相对复杂。
ureq简单的HTTP请求、脚本化的网络操作轻量级的HTTP库,API简单,但功能相对较少。

适用场景:在需要处理大量并发请求的场景下,如Web服务的API调用、爬虫开发等,reqwest 是更好的选择。而对于需要自定义HTTP协议或进行底层HTTP服务开发的场景,hyper 更合适。如果只是进行简单的HTTP请求,ureq 则可以满足需求。

二、核心功能详解

2.1 基础篇

2.1.1 同步/异步双模式配置

reqwest 支持同步和异步两种模式,开发者可以根据具体需求选择合适的模式。

// 同步模式(blocking模式)
use reqwest::blocking::get;fn main() -> Result<(), reqwest::Error> {let response = get("<https://httpbin.org/json>")?;println!("Status: {}", response.status());println!("Body: {}", response.text()?);Ok(())
}// 异步模式
use reqwest;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let response = reqwest::get("<https://httpbin.org/json>").await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:同步模式下,程序会阻塞直到请求完成,适合简单的脚本或对并发要求不高的场景。异步模式下,请求会在后台执行,程序可以继续执行其他任务,适合高并发场景。

适用场景:脚本化的网络操作可以使用同步模式,而高并发的Web服务或爬虫开发则应使用异步模式。

2.1.2 请求构建器模式(Builder Pattern)

请求构建器模式允许开发者通过链式调用的方式构建复杂的请求。

use reqwest;
use std::time::Duration;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let client = reqwest::Client::new();let url = "<https://httpbin.org/post>";let response = client.post(url).header("X-Custom-Header", "value").timeout(Duration::from_secs(30)).basic_auth("user", Some("pass")).send().await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:reqwest::Client::new() 创建一个客户端实例,通过链式调用 post()header()timeout() 等方法可以设置请求的各种参数,最后调用 send() 方法发送请求。

适用场景:需要设置多个请求参数的场景,如发送带有自定义头部、认证信息和超时设置的请求。

2.2 进阶篇

2.2.1 连接池调优(keep-alive配置)

连接池可以复用已经建立的连接,减少连接建立和关闭的开销,提高性能。

use reqwest;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let client = reqwest::Client::builder().pool_idle_timeout(std::time::Duration::from_secs(30)) // ⚠️ 空闲连接的超时时间.pool_max_idle_per_host(5) // ⚠️ 每个主机的最大空闲连接数.build()?;let response = client.get("<https://httpbin.org/json>").await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:reqwest::Client::builder() 用于创建一个可配置的客户端实例,通过 pool_idle_timeout()pool_max_idle_per_host() 方法可以设置连接池的参数。

适用场景:需要频繁发送请求的场景,如API客户端或爬虫开发。

2.2.2 自动重试与超时策略

可以通过自定义重试逻辑和超时设置来处理请求失败的情况。

use reqwest;
use std::time::Duration;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let client = reqwest::Client::builder().timeout(Duration::from_secs(5)) // ⚠️ 请求超时时间.build()?;let mut retry_count = 0;let max_retries = 3;loop {match client.get("<https://httpbin.org/json>").await {Ok(response) => {println!("Status: {}", response.status());println!("Body: {}", response.text().await?);break;}Err(err) => {if retry_count >= max_retries {return Err(err);}retry_count += 1;println!("Request failed, retrying ({}/{})...", retry_count, max_retries);}}}Ok(())
}

操作原理说明:通过 timeout() 方法设置请求超时时间,使用循环和计数器实现自动重试逻辑。

适用场景:网络不稳定的环境下,如移动网络或跨地域的请求。

2.2.3 多部分文件上传(multipart/form-data)

可以使用 reqwest 进行多部分文件上传。

use reqwest;
use std::fs::File;
use std::io::BufReader;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let client = reqwest::Client::new();let file = File::open("example.txt")?;let reader = BufReader::new(file);let form = reqwest::multipart::Form::new().text("field1", "value1").part("file", reqwest::multipart::Part::reader(reader).file_name("example.txt"));let response = client.post("<https://httpbin.org/post>").multipart(form).send().await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:使用 reqwest::multipart::Form::new() 创建一个表单实例,通过 text()part() 方法添加表单字段和文件,最后使用 multipart() 方法将表单添加到请求中。

适用场景:需要上传文件的场景,如图片上传、文件备份等。

2.2.4 代理服务器与TOR网络集成

可以通过设置代理服务器来隐藏请求的真实来源,也可以集成TOR网络实现匿名请求。

use reqwest;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let proxy = reqwest::Proxy::http("<http://proxy.example.com:8080>")?;let client = reqwest::Client::builder().proxy(proxy).build()?;let response = client.get("<https://httpbin.org/json>").await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:使用 reqwest::Proxy::http() 创建一个代理实例,通过 proxy() 方法将代理添加到客户端中。

适用场景:需要隐藏请求来源或突破网络限制的场景,如爬虫开发、网络测试等。

2.2.5 Cookie持久化实战

可以将Cookie存储到文件中,实现Cookie的持久化。

use reqwest;
use std::fs::File;
use std::io::{Read, Write};
use serde_json;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let client = reqwest::Client::new();let response = client.get("<https://httpbin.org/cookies/set?name=value>").await?;let cookies = response.cookies().cloned().collect::<Vec<_>>();let cookies_json = serde_json::to_string(&cookies)?;let mut file = File::create("cookies.json")?;file.write_all(cookies_json.as_bytes())?;println!("Cookies saved to cookies.json");Ok(())
}

操作原理说明:通过 response.cookies() 方法获取响应中的Cookie,使用 serde_json 将Cookie序列化为JSON字符串,最后将JSON字符串写入文件。

适用场景:需要保持会话状态的场景,如登录后的后续请求。

2.3 企业级特性

2.3.1 自定义TLS后端(rustls vs native-tls)

reqwest 支持使用 rustlsnative-tls 作为TLS后端。

use reqwest;
use reqwest::ClientBuilder;
use rustls::ClientConfig;
use rustls::RootCertStore;
use webpki_roots::TLS_SERVER_ROOTS;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let mut root_store = RootCertStore::empty();root_store.add_server_trust_anchors(TLS_SERVER_ROOTS.0.iter().map(|ta| {rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(ta.subject,ta.spki,ta.name_constraints,)}));let tls_config = ClientConfig::builder().with_safe_defaults().with_root_certificates(root_store).with_no_client_auth();let client = ClientBuilder::new().use_rustls_tls().tls_config(tls_config).build()?;let response = client.get("<https://httpbin.org/json>").await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:通过 ClientBuilder::new() 创建一个可配置的客户端实例,使用 use_rustls_tls() 方法指定使用 rustls 作为TLS后端,通过 tls_config() 方法设置TLS配置。

适用场景:对TLS安全性有较高要求的场景,如金融交易、敏感数据传输等。

2.3.2 请求/响应拦截器(类似Axios的interceptor)

可以通过自定义中间件实现请求/响应拦截器。

use reqwest;
use reqwest::ClientBuilder;
use reqwest_middleware::{ClientBuilder as MiddlewareClientBuilder, RequestBuilder, Result};
use reqwest_tracing::TracingMiddleware;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let client = ClientBuilder::new().build()?;let middleware_client = MiddlewareClientBuilder::new(client).with(TracingMiddleware::default()).build();let request = middleware_client.get("<https://httpbin.org/json>");let response = request.send().await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:使用 reqwest_middleware 库创建一个带有中间件的客户端,通过 with() 方法添加中间件,中间件可以在请求发送前和响应返回后进行拦截和处理。

适用场景:需要对请求和响应进行统一处理的场景,如日志记录、错误处理等。

2.3.3 分布式追踪集成(OpenTelemetry)

可以将 reqwestOpenTelemetry 集成,实现分布式追踪。

use reqwest;
use opentelemetry::global;
use opentelemetry::sdk::trace as sdktrace;
use opentelemetry::trace::Tracer;
use reqwest_middleware::ClientBuilder;
use reqwest_tracing::TracingMiddleware;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let tracer = init_tracer();let client = reqwest::Client::new();let middleware_client = ClientBuilder::new(client).with(TracingMiddleware::default()).build();let span = tracer.start("http_request");let _guard = span.enter();let response = middleware_client.get("<https://httpbin.org/json>").send().await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);span.end();global::shutdown_tracer_provider();Ok(())
}fn init_tracer() -> impl Tracer {let tracer = sdktrace::TracerProvider::builder().with_simple_exporter(sdktrace::stdout::new_exporter()).build();global::set_tracer_provider(tracer);global::tracer("reqwest_example")
}

操作原理说明:使用 opentelemetry 库创建一个追踪器,通过 reqwest_middlewarereqwest_tracing 库将追踪器集成到 reqwest 客户端中,在请求发送时记录追踪信息。

适用场景:分布式系统中,需要对请求进行追踪和性能分析的场景。

2.3.4 压力测试与性能调优指标

可以使用 wrk 等工具对 reqwest 应用进行压力测试,通过调整连接池大小、超时时间等参数进行性能调优。

配置参数吞吐量(请求/秒)响应时间(毫秒)
默认配置100050
连接池大小=100150040
超时时间=10秒120060

适用场景:需要对应用的性能进行评估和优化的场景,如生产环境的性能调优。

三、实战项目演示

3.1 构建带有缓存层的REST API客户端

可以使用 reqwest 构建一个带有缓存层的REST API客户端,减少重复请求。

use reqwest;
use std::collections::HashMap;
use std::time::Duration;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let mut cache: HashMap<String, String> = HashMap::new();let client = reqwest::Client::new();let url = "<https://httpbin.org/json>";if let Some(cached_response) = cache.get(url) {println!("Using cached response: {}", cached_response);} else {let response = client.get(url).timeout(Duration::from_secs(5)).send().await?;let body = response.text().await?;cache.insert(url.to_string(), body.clone());println!("New response: {}", body);}Ok(())
}

操作原理说明:使用 HashMap 作为缓存,在发送请求前先检查缓存中是否存在该请求的响应,如果存在则直接使用缓存,否则发送请求并将响应存入缓存。

适用场景:需要频繁访问相同API的场景,如数据查询、配置获取等。

3.2 实现自动切换代理的爬虫框架

可以使用 reqwest 实现一个自动切换代理的爬虫框架,提高爬虫的稳定性。

use reqwest;
use std::time::Duration;
use rand::seq::SliceRandom;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let proxies = vec!["<http://proxy1.example.com:8080>","<http://proxy2.example.com:8080>","<http://proxy3.example.com:8080>",];let mut rng = rand::thread_rng();let client = reqwest::Client::builder().timeout(Duration::from_secs(10)).build()?;let url = "<https://httpbin.org/json>";let mut retry_count = 0;let max_retries = 3;loop {let proxy = proxies.choose(&mut rng).unwrap();let proxy_obj = reqwest::Proxy::http(proxy)?;let proxy_client = client.clone().proxy(proxy_obj);match proxy_client.get(url).send().await {Ok(response) => {println!("Status: {}", response.status());println!("Body: {}", response.text().await?);break;}Err(err) => {if retry_count >= max_retries {return Err(err);}retry_count += 1;println!("Request failed with proxy {}, retrying ({}/{})...", proxy, retry_count, max_retries);}}}Ok(())
}

操作原理说明:首先定义一个代理列表,使用 rand 库随机选择一个代理。创建一个 reqwest 客户端,并通过 proxy() 方法设置代理。发送请求,如果请求失败则重试,最多重试 max_retries 次,每次重试时重新选择代理。

适用场景:Web 爬虫开发,尤其是在需要突破网站反爬机制或应对网络限制的情况下,自动切换代理可以提高爬虫的稳定性和成功率。

3.3 与 Serde 深度集成的类型安全 HTTP 交互

可以结合 reqwestserde 实现类型安全的 HTTP 交互,将响应数据自动反序列化为 Rust 结构体。

use reqwest;
use serde::Deserialize;#[derive(Debug, Deserialize)]
struct ExampleResponse {origin: String,headers: serde_json::Value,
}#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let client = reqwest::Client::new();let url = "<https://httpbin.org/json>";let response = client.get(url).send().await?;let data: ExampleResponse = response.json().await?;println!("Origin: {}", data.origin);println!("Headers: {:?}", data.headers);Ok(())
}

操作原理说明:定义一个 Rust 结构体 ExampleResponse,并使用 serdeDeserialize 特性进行标注。发送 HTTP 请求后,使用 response.json().await? 方法将响应数据自动反序列化为 ExampleResponse 结构体。

适用场景:与 API 进行交互时,需要将响应数据进行结构化处理的场景,如解析 JSON 数据、处理 XML 数据等,类型安全的交互可以避免手动解析数据时可能出现的错误。

四、调试技巧

4.1 使用 reqwest - middleware 增强日志

reqwest - middleware 可以帮助我们记录请求和响应的详细信息,方便调试。

use reqwest;
use reqwest_middleware::{ClientBuilder, Result};
use reqwest_tracing::TracingMiddleware;
use tracing_subscriber::FmtSubscriber;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let subscriber = FmtSubscriber::builder().with_max_level(tracing::Level::DEBUG).finish();tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");let client = reqwest::Client::new();let middleware_client = ClientBuilder::new(client).with(TracingMiddleware::default()).build();let response = middleware_client.get("<https://httpbin.org/json>").send().await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:使用 tracing_subscriber 配置日志级别为 DEBUG,通过 reqwest_middlewarereqwest_tracing 库将日志功能集成到 reqwest 客户端中。在请求发送和响应返回时,会记录详细的日志信息。

适用场景:开发和调试阶段,需要详细了解请求和响应信息的场景。

4.2 通过 mitmproxy 抓包分析

mitmproxy 是一个强大的抓包工具,可以拦截和分析 HTTP 请求和响应。

  1. 启动 mitmproxy:在终端中运行 mitmproxy 命令。
  2. 配置 reqwest 客户端使用 mitmproxy 代理:
use reqwest;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let proxy = reqwest::Proxy::http("<http://127.0.0.1:8080>")?;let client = reqwest::Client::builder().proxy(proxy).build()?;let response = client.get("<https://httpbin.org/json>").send().await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:启动 mitmproxy 后,它会在本地监听 8080 端口。配置 reqwest 客户端使用该代理,所有的请求和响应都会经过 mitmproxy,可以在 mitmproxy 的界面中查看详细信息。

适用场景:需要分析请求和响应的具体内容,排查网络问题的场景。

4.3 常见错误代码速查表

错误代码含义解决方法
CE3023连接池耗尽增加连接池大小,检查是否有大量未释放的连接
E0433找不到类型或模块检查依赖是否正确安装,模块路径是否正确
E0308类型不匹配检查变量类型,确保数据类型一致

适用场景:在开发和调试过程中,遇到错误代码时可以快速查找原因和解决方法。

五、扩展阅读

5.1 与 tower 生态的集成路径

tower 是一个用于构建异步服务的模块化框架,reqwest 可以与 tower 生态集成,实现更复杂的中间件和服务组合。

use reqwest;
use tower::ServiceBuilder;
use tower_http::trace::TraceLayer;#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let client = reqwest::Client::builder().build()?;let service = ServiceBuilder::new().layer(TraceLayer::new_for_http()).service(client);let request = reqwest::Request::builder().method(reqwest::Method::GET).uri("<https://httpbin.org/json>").body(None).unwrap();let response = service.call(request).await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:使用 ServiceBuilder 构建一个服务,通过 layer() 方法添加 TraceLayer 中间件,将 reqwest 客户端作为服务的底层实现。

适用场景:需要构建复杂的异步服务,对请求进行更精细处理的场景。

5.2 基于 reqwest 构建 SDK 的设计模式

可以基于 reqwest 构建 SDK,常见的设计模式有工厂模式、单例模式等。

use reqwest;pub struct MySdk {client: reqwest::Client,
}impl MySdk {pub fn new() -> Self {let client = reqwest::Client::new();MySdk { client }}pub async fn get_data(&self, url: &str) -> Result<reqwest::Response, reqwest::Error> {self.client.get(url).send().await}
}#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {let sdk = MySdk::new();let response = sdk.get_data("<https://httpbin.org/json>").await?;println!("Status: {}", response.status());println!("Body: {}", response.text().await?);Ok(())
}

操作原理说明:定义一个 MySdk 结构体,在 new() 方法中创建 reqwest 客户端。通过 get_data() 方法封装请求逻辑,提供统一的接口供外部调用。

适用场景:开发面向第三方的 SDK,需要对 reqwest 进行封装和抽象的场景。

5.3 WASM 环境下的特殊限制

在 WebAssembly(WASM)环境下使用 reqwest 有一些特殊限制,如不支持同步请求,需要使用异步请求。

use wasm_bindgen_futures::spawn_local;
use reqwest;#[wasm_bindgen(start)]
pub async fn main() -> Result<(), reqwest::Error> {let response = reqwest::get("<https://httpbin.org/json>").await?;let text = response.text().await?;console_log!("Response: {}", text);Ok(())
}

操作原理说明:在 WASM 环境下,使用 wasm_bindgen_futures::spawn_local 来执行异步任务,使用 reqwest::get() 方法发送异步请求。

适用场景:开发基于 WebAssembly 的前端应用,需要进行网络请求的场景。

流程图和时序图

自动切换代理的爬虫框架流程图

开始
选择代理
发送请求
请求成功?
处理响应
重试次数达到上限?
结束并报错
结束

带有缓存层的 REST API 客户端流程图

开始
缓存中是否存在数据?
使用缓存数据
发送请求
处理响应
将响应存入缓存
结束

与 Serde 集成的类型安全 HTTP 交互时序图

Client Server 发送 HTTP 请求 返回 HTTP 响应 使用 Serde 反序列化响应数据 处理反序列化后的数据 Client Server

Cargo.toml 依赖模板

[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rand = "0.8"
tracing = "0.1"
tracing-subscriber = "0.3"
reqwest-middleware = "0.10"
reqwest-tracing = "0.6"
tower = "0.4"
tower-http = "0.4"
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"

各功能的 MSRV(最低支持 Rust 版本)

功能MSRV
基础功能1.46.0
异步模式1.46.0
连接池调优1.46.0
自动重试与超时策略1.46.0
多部分文件上传1.46.0
代理服务器与 TOR 网络集成1.46.0
Cookie 持久化1.46.0
自定义 TLS 后端1.46.0
请求/响应拦截器1.46.0
分布式追踪集成1.46.0
与 Serde 集成1.46.0
与 tower 生态集成1.46.0
WASM 环境支持1.46.0

通过以上内容,你可以全面深入地掌握 reqwest 库的高级用法,无论是在开发生产级的 HTTP 客户端,还是构建复杂的网络应用,都能游刃有余。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79584.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s中sidecar死循环

序言 怎么发现我的同事们很上进呢&#xff0c;估计做了下贱的事儿吧。 伤不到我&#xff0c;不代表不疼&#xff01; sidecar产生的问题 1 背景 在k8s的环境中&#xff0c;pod的使用越来越多了&#xff0c;也就产生了sidecar容器&#xff0c;在现在的环境中&#xff0c;一个pod…

Day53 二叉树的层序遍历

给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* T…

C盘清理技巧分享

一、系统级深度清理 1. 存储感知自动化 路径:设置 → 系统 → 存储 → 开启「存储感知」配置策略: 临时文件:每 1-2 周自动清理回收站:超过 30 天自动清空应用缓存:按需求设置清理频率进阶操作:在「高级存储设置」中关闭「传递优化」(减少更新缓存占用)2. 磁盘清理工具…

面试题--随机(一)

MySQL事务中的ACID特性&#xff1f; A 原子性 事务是一组SQL语句&#xff0c;不可分割 C 一致性 事务中的SQL语句要么同时执行&#xff0c;即全部执行成功&#xff0c;要么全部不执行&#xff0c;即执行失败 I 隔离性 MySQL中的各个事务通过不同的事务隔离等级&#xff0c;产生…

Spring Boot资源耗尽问题排查与优化

Spring Boot服务运行一段时间后新请求无法处理的问题。服务没有挂掉&#xff0c;也没有异常日志。思考可能是一些资源耗尽或阻塞的问题。 思考分析 首先&#xff0c;资源耗尽可能涉及线程池、数据库连接、内存、文件句柄或网络连接等。常见的如线程池配置不当&#xff0c;导致…

Map和Set相关练习

目录 1、只出现一次的数字 2、宝石与石头 3、坏键盘打字 4、复制带随机指针的链表 5、大量数据去重 6、大量数据重复次数 7、前K个高频单词 1、只出现一次的数字 oj&#xff1a;136. 只出现一次的数字 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 1. 使用…

day45——非递减数列(LeetCode-665)

题目描述 给你一个长度为 n 的整数数组 nums &#xff0c;请你判断在 最多 改变 1 个元素的情况下&#xff0c;该数组能否变成一个非递减数列。 我们是这样定义一个非递减数列的&#xff1a; 对于数组中任意的 i (0 < i < n-2)&#xff0c;总满足 nums[i] < nums[i …

OOM 未触发 JVM 崩溃的可能原因

1. OOM 未触发 JVM 崩溃的可能原因‌ (1) 未配置 JVM 参数强制崩溃‌ 关键参数缺失‌&#xff1a; 若未添加 -XX:CrashOnOutOfMemoryError&#xff0c;JVM 在 OOM 时可能仅抛出异常并正常退出&#xff0c;而非崩溃&#xff0c;因此不会生成 hs_err_pid.log。 # 正确配置示例&…

Axios 介绍及使用指南

本文将基于 Axios 原理&#xff0c;安装及封装方面展开描述&#xff0c;话不多说&#xff0c;现在发车&#xff01; 一、原理 Axios 中文文档&#xff1a;起步 | Axios中文文档 | Axios中文网 赛前科普&#xff1a; 下文将涉及到三个关键词&#xff1a;Axios&#xff0c;Ajax…

C#插件与可扩展性

外接程序为主机应用程序提供了扩展功能或服务。.net framework提供了一个编程模型,开发人员可以使用该模型来开发加载项并在其主机应用程序中激活它们。该模型通过在主机和外接程序之间构建通信管道来实现此目的。该模型是使用: System.AddIn, System.AddIn.Hosting, System.…

Melos 发布pub.dev

确保登录 置登录状态 按照提示操作&#xff0c;先运行&#xff1a; bash dart pub logout 这会清除当前的&#xff08;损坏的&#xff09;登录信息。 然后再重新登录&#xff1a; bash dart pub login 这一次它应该会在浏览器中打开 Google 登录页面&#xff0c;完成登…

4.黑马学习笔记-SpringMVC(P43-P47)

1.SpringMVC简介 SpringMVC技术&#xff08;更少的代码&#xff0c;简便&#xff09;与servlet技术功能相同&#xff0c;属于web层开发技术。 SpringMVC是一种基于java实现MVC模型的轻量级web框架。 轻量级指的是&#xff08;内存占用比较低&#xff0c;运行效率高&#xff09;…

【特殊场景应对1】视觉设计:信息密度与美学的博弈——让简历在HR视网膜上蹦迪的科学指南

写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…

CentOS 7 linux系统从无到有部署项目

环境部署操作手册 一、Maven安装与配置 1. 下载与解压 下载地址&#xff1a;https://maven.apache.org/download.cgi?spm5238cd80.38b417da.0.0.d54c32cbnOpQh2&filedownload.cgi上传并解压解压命令&#xff1a; tar -zxvf apache-maven-3.9.9-bin.tar.gz -C /usr/loc…

Odoo:免费开源的轧制品行业管理软件

Odoo免费开源的轧制品行业管理软件能够帮助建材、电线电缆、金属、造纸包装以及纺织品行业提高韧性和盈利能力&#xff0c;构筑美好未来。 文 &#xff5c; 开源智造&#xff08;OSCG&#xff09;Odoo金牌服务 提高供应链韧性&#xff0c;赋能可持续发展 如今&#xff0c;金属…

51单片机实验二:数码管静态显示

目录 一、实验环境与实验器材 二、实验内容及实验步骤 1.单个数码管显示 2.六个数码管依次从0~F变换显示 3.proteus仿真 一、实验环境与实验器材 环境&#xff1a;Keli&#xff0c;STC-ISP烧写软件,Proteus. 器材&#xff1a;TX-1C单片机&#xff08;STC89C52RC…

学术AI工具推荐

一、基础信息对比 维度知网研学AI&#xff08;研学智得AI&#xff09;秘塔AIWOS AI开发公司同方知网&#xff08;CNKI&#xff09;上海秘塔网络科技Clarivate Analytics是否接入DeepSeek✅ 深度集成&#xff08;全功能接入DeepSeek-R1推理服务&#xff09;✅ 通过API接入DeepS…

冰川流域提取分析——ArcGIS pro

一、河网提取和流域提取视频详细GIS小熊 || 6分钟学会水文分析—河网提取&#xff08;以宜宾市为例&#xff09;_哔哩哔哩_bilibili 首先你要生成研究区域DEM&#xff0c;然后依次是填洼→流向→流量→栅格计算器→河网分级→栅格河网矢量化&#xff08;得到河网.shp&#xff…

【物联网-RS-485】

物联网-RS-485 ■ RS-485 连接方式■ RS-485 半双工通讯■ RS-485 的特点 ■ RS-485 连接方式 ■ RS-485 半双工通讯 一线定义为A 一线定义为B RS-485传输方式&#xff1a;半双工通信、&#xff08;逻辑1&#xff1a;2V ~ 6V 逻辑0&#xff1a;-6V ~ -2V&#xff09;这里的电平…

解析检验平板:设备还是非设备?深入了解其功能与应用(北重铸铁平台厂家)

检验平板通常被归类为设备&#xff0c;因为它们具有特定的功能&#xff0c;并且被用于测试和评估其他设备或产品的性能和质量。检验平板通常具有平坦的表面&#xff0c;用于放置要进行测试或检验的物品。它们可以用于测量尺寸、形状、平整度、表面光洁度等参数。 检验平板的应…