Rust Axum 快速上手指南(靜態網頁和動態網頁2024版)

本文基于?Axum 0.7.5(當前穩定版)、tower-http 0.5.2MiniJinja 0.7.2?編寫,涵蓋生產環境核心場景:tower-http Layer 疊加與數據傳遞靜態網頁服務MiniJinja 動態模板渲染,并重點解析請求 / 應答在多 Layer 中的流轉邏輯。

一、環境準備:依賴配置

首先在?Cargo.toml?中添加最新依賴,確保組件兼容性(Axum 0.7+ 需搭配 tower-http 0.5+):

[package]
name = "axum-demo"
version = "0.1.0"
edition = "2021"[dependencies]
# Axum 核心(含路由、Handler、State 等)
axum = { version = "0.7.5", features = ["json", "macros"] }
# 異步運行時(Axum 依賴 tokio)
tokio = { version = "1.35.1", features = ["full"] }
# HTTP 中間件生態(Layer 核心)
tower-http = { version = "0.5.2", features = ["trace",    # 日志追蹤"compression-br",  # Brotli 壓縮"cors",     # 跨域支持"serve-dir",# 靜態文件服務"request-body-limit", # 請求大小限制"fs",       # 文件系統操作
] }
# 日志格式化(配合 tower-http::trace)
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
# 動態模板引擎
minijinja = "0.7.2"
# 路徑處理
std-fs = "0.1.4"

二、核心概念鋪墊

在深入 Layer 之前,需明確 Axum 生態的 3 個核心組件:

  1. Handler:處理 HTTP 請求的函數(如?async fn hello() -> &'static str),是請求處理的「終點」。
  2. Router:路由分發器,將請求匹配到對應的 Handler,支持嵌套和掛載。
  3. Layer:中間件抽象,用于攔截 / 修改請求(Request)或應答(Response),可疊加使用(如日志、壓縮、跨域)。

關鍵邏輯:Layer 會「包裝」Router 或下一層 Layer,形成一個「洋蔥模型」—— 請求從外層 Layer 流向內層 Handler,應答從內層 Handler 流回外層 Layer。


三、tower-http Layer 疊加與數據傳遞

3.1 Layer 核心規則:洋蔥模型

Layer 的執行順序遵循?「請求外→內,應答內→外」,即:

  • 請求階段:先添加的 Layer 先處理請求(如先日志 → 再壓縮 → 最后到 Handler)。
  • 應答階段:先添加的 Layer 后處理應答(如 Handler 生成應答 → 壓縮 → 日志 → 客戶端)。

下圖直觀展示多 Layer 數據流轉:

客戶端 → [TraceLayer(日志)] → [CompressionLayer(壓縮)] → [CorsLayer(跨域)] → Router → Handler↑                                  ↓
客戶端 ← [TraceLayer(日志)] ← [CompressionLayer(壓縮)] ← [CorsLayer(跨域)] ← Router ← Handler

3.2 生產環境常用 Layer 配置

以下是現實項目中必選的 Layer 組合,按「外層到內層」順序添加(優化性能和安全性):

步驟 1:初始化日志(TraceLayer)

用于記錄請求方法、路徑、狀態碼、耗時等,是調試和監控的核心。

步驟 2:跨域處理(CorsLayer)

解決瀏覽器跨域問題,需明確允許的 Origin、Method、Header。

步驟 3:請求大小限制(RequestBodyLimitLayer)

防止超大請求攻擊(如上傳惡意文件),生產環境建議限制 10MB 以內。

步驟 4:壓縮(CompressionLayer)

減少響應體積,支持 Brotli、Gzip(Brotli 壓縮率更高,優先啟用)。

代碼實現:Layer 疊加
use axum::{Router, Server};
use tower_http::{compression::CompressionLayer,cors::{Any, CorsLayer},request_body_limit::RequestBodyLimitLayer,trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer},
};
use tracing_subscriber::{prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt};#[tokio::main]
async fn main() {// 1. 初始化日志(必須先啟動,否則 Layer 日志不生效)tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| "axum_demo=debug,tower_http=debug".into()),).with(tracing_subscriber::fmt::layer()).init();// 2. 構建核心路由(后續添加靜態/動態路由)let app_router = Router::new();// 3. 疊加 Layer(順序:外層→內層,影響請求/應答處理順序)let app = app_router// Layer 1:日志追蹤(最外層,優先記錄完整請求).layer(TraceLayer::new_for_http().make_span_with(DefaultMakeSpan::new().include_headers(true)) // 記錄請求頭.on_response(DefaultOnResponse::new().include_headers(true)), // 記錄響應頭)// Layer 2:跨域(外層,先驗證跨域,避免后續無用處理).layer(CorsLayer::new().allow_origin(Any) // 生產環境替換為具體域名(如 "https://example.com").allow_methods(Any).allow_headers(Any),)// Layer 3:請求大小限制(10MB).layer(RequestBodyLimitLayer::new(10 * 1024 * 1024))// Layer 4:壓縮(內層,靠近 Handler,減少數據傳輸).layer(CompressionLayer::new().br(true).gzip(true));// 啟動服務Server::bind(&([127, 0, 0, 1], 3000).into()).serve(app.into_make_service()).await.unwrap();
}

3.3 請求 / 應答在多 Layer 中的數據傳遞細節

每個 Layer 本質是一個「Service 包裝器」,通過?Service::call?方法傳遞請求,具體流程:

  1. 請求階段(Request Flow)

    • 客戶端發送 HTTP 請求 → 進入最外層 Layer(如 TraceLayer)。
    • TraceLayer 記錄請求開始時間、方法、路徑 → 調用下一層 Layer(CorsLayer)的?call?方法,傳遞修改后的 Request(或原 Request)。
    • CorsLayer 檢查請求的 Origin/Method → 若合法,調用下一層(RequestBodyLimitLayer)→ 否則直接返回 403 應答。
    • RequestBodyLimitLayer 檢查請求體大小 → 若超限,返回 413 應答 → 否則傳遞給 CompressionLayer。
    • CompressionLayer 不修改請求(僅處理應答)→ 傳遞給 Router → Router 匹配 Handler → Handler 處理請求并生成 Response。
  2. 應答階段(Response Flow)

    • Handler 生成 Response → 回傳給 CompressionLayer。
    • CompressionLayer 檢查 Response 的 Content-Type(如文本、HTML)→ 若支持壓縮,對響應體進行 Brotli/Gzip 壓縮 → 添加上?Content-Encoding?頭 → 回傳給 RequestBodyLimitLayer。
    • RequestBodyLimitLayer 不處理應答 → 回傳給 CorsLayer。
    • CorsLayer 為 Response 添加?Access-Control-Allow-*?頭 → 回傳給 TraceLayer。
    • TraceLayer 記錄應答的狀態碼、耗時 → 將最終 Response 發送給客戶端。

3.4 自定義 Layer 示例(直觀理解流轉)

若需驗證 Layer 執行順序,可自定義一個打印日志的 Layer,觀察請求 / 應答的處理時機:

use axum::body::Body;
use http::{Request, Response};
use tower::{Layer, Service};
use std::task::{Context, Poll};// 自定義 Layer(無狀態,僅打印日志)
#[derive(Clone, Copy, Default)]
struct LogLayer;impl<S> Layer<S> for LogLayer {type Service = LogService<S>;fn layer(&self, inner: S) -> Self::Service {LogService { inner }}
}// Layer 對應的 Service(實際處理邏輯)
struct LogService<S> {inner: S,
}impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for LogService<S>
whereS: Service<Request<ReqBody>, Response = Response<ResBody>>,S::Error: std::fmt::Display,
{type Response = S::Response;type Error = S::Error;type Future = futures::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {self.inner.poll_ready(cx)}fn call(&mut self, req: Request<ReqBody>) -> Self::Future {// 請求階段:打印請求信息(外層 Layer 先執行)println!("[LogLayer] 收到請求: {} {}", req.method(), req.uri().path());// 保存 inner 的引用(因 async 閉包無法捕獲 &mut self)let mut inner = self.inner.clone();Box::pin(async move {// 調用下一層 Service(傳遞請求)let resp = inner.call(req).await?;// 應答階段:打印應答信息(內層 Layer 先執行)println!("[LogLayer] 返回應答: {}", resp.status());Ok(resp)})}
}// 在 main 中添加自定義 Layer(放在 TraceLayer 之后,觀察順序)
// let app = app_router
//     .layer(TraceLayer::new_for_http(...))
//     .layer(LogLayer)  // 自定義 Layer
//     .layer(CorsLayer::new(...))
//     ...;

運行后,請求?GET /?會輸出:

[LogLayer] 收到請求: GET /  # 請求階段:先 Trace → 再 Log → 再 Cors...
[LogLayer] 返回應答: 200 OK  # 應答階段:先 Handler → 再 Compression → 再 Log → 再 Trace...

四、Serve 靜態網頁

使用?tower-http::serve_dir::ServeDir?實現靜態文件服務(如 HTML、CSS、JS、圖片),支持路徑映射和 404 處理。

4.1 基礎靜態服務(映射本地目錄)

假設本地有?static?目錄,結構如下:

static/index.html  # 首頁css/style.css # 樣式文件img/logo.png  # 圖片

代碼實現:掛載?/static?路徑到本地?static?目錄:

use axum::Router;
use tower_http::serve_dir::ServeDir;// 在 main 中構建路由
let app_router = Router::new()// 掛載靜態文件:請求 /static/xxx → 讀取 static/xxx.nest_service("/static", ServeDir::new("static"))// 根路徑(/)重定向到 /static/index.html.route("/", axum::routing::get(|| async {axum::response::Redirect::permanent("/static/index.html")}));

啟動服務后,訪問以下路徑會返回對應文件

  • http://127.0.0.1:3000/?→ 重定向到?index.html
  • http://127.0.0.1:3000/static/css/style.css?→ 返回樣式文件
  • http://127.0.0.1:3000/static/img/logo.png?→ 返回圖片

4.2 高級配置:自定義 404 頁面

當請求的靜態文件不存在時,默認返回 404 空白頁,可自定義 404 頁面:

use axum::{response::IntoResponse, http::StatusCode};
use tower_http::serve_dir::ServeDir;// 自定義 404 響應(HTML 格式)
async fn not_found() -> impl IntoResponse {(StatusCode::NOT_FOUND,axum::response::Html("<h1>404 - 頁面不存在</h1><p>請檢查路徑是否正確</p>"),)
}// 構建路由時,用 `fallback` 處理 404
let app_router = Router::new().nest_service("/static", ServeDir::new("static").not_found_service(// 靜態文件不存在時,調用 not_found Handleraxum::routing::get(not_found))).route("/", axum::routing::get(|| async {axum::response::Redirect::permanent("/static/index.html")}))// 其他路徑(非 /static)也返回 404.fallback(not_found);

4.3 生產環境優化:添加緩存頭

為靜態文件添加?Cache-Control?頭,減少重復請求(使用?tower-http::cache_control::CacheControlLayer):

use tower_http::cache_control::{CacheControlLayer, CacheControl};// 在 Layer 疊加中添加緩存控制(放在 CompressionLayer 之后,靠近靜態服務)
let app = app_router.layer(TraceLayer::new_for_http(...)).layer(CorsLayer::new(...)).layer(RequestBodyLimitLayer::new(10 * 1024 * 1024)).layer(CompressionLayer::new().br(true).gzip(true))// 靜態文件緩存:設置 max-age=3600(1 小時).layer(CacheControlLayer::new().with_cache_control(CacheControl::new().max_age(std::time::Duration::from_secs(3600)))// 僅對靜態文件路徑生效.on_route(|route| route.starts_with("/static/")),);

五、MiniJinja 模板動態網頁

MiniJinja 是輕量、安全的模板引擎,支持變量、循環、條件判斷、模板繼承,適合生成動態 HTML(如用戶中心、列表頁)。

5.1 模板目錄結構

先創建?templates?目錄,存放模板文件,推薦結構:

templates/base.html    # 基礎模板(公共頭部、尾部)index.html   # 首頁(繼承 base.html)users.html   # 用戶列表頁(繼承 base.html)

5.2 初始化 MiniJinja 模板環境

模板環境(TemplateEnvironment)需全局共享(通過 Axum 的?State?傳遞),避免重復初始化:

use axum::{Router, extract::State, response::Html};
use minijinja::{Environment, Template};
use std::sync::Arc;// 定義全局狀態(包裝 MiniJinja 環境)
#[derive(Clone)]
struct AppState {template_env: Arc<Environment<'static>>,
}// 初始化模板環境
fn init_template_env() -> Environment<'static> {let mut env = Environment::new();// 添加模板目錄(加載 .html 文件)env.add_template_dir("templates").expect("Failed to add template directory");// 可選:添加自定義過濾器(如日期格式化)env.add_filter("upper", |s: &str| s.to_uppercase());env
}#[tokio::main]
async fn main() {// 初始化模板環境并包裝為全局狀態let template_env = Arc::new(init_template_env());let app_state = AppState { template_env };// 構建路由(通過 with_state 傳遞全局狀態)let app_router = Router::new().route("/", axum::routing::get(render_index)).route("/users", axum::routing::get(render_users)).with_state(app_state); // 傳遞全局狀態// 疊加 Layer 并啟動服務(同前)// ...
}

5.3 編寫模板文件

1. 基礎模板(base.html)

使用?{% block %}?定義可替換的區塊,供子模板繼承:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>{% block title %}默認標題{% endblock %}</title><link rel="stylesheet" href="/static/css/style.css">
</head>
<body><header><h1>Axum MiniJinja 示例</h1><nav><a href="/">首頁</a> | <a href="/users">用戶列表</a></nav></header><!-- 子模板內容區域 --><main>{% block content %}{% endblock %}</main><footer><p>? 2024 Axum 開發指南</p></footer>
</body>
</html>
2. 首頁模板(index.html)

繼承?base.html,填充?title?和?content?區塊:

{% extends "base.html" %}{% block title %}首頁 - Axum 示例{% endblock %}{% block content %}<h2>歡迎訪問首頁</h2><p>當前時間:{{ current_time }}</p><p>用戶名:{{ username | upper }}</p> <!-- 使用自定義 upper 過濾器 -->
{% endblock %}
3. 用戶列表模板(users.html)

使用?{% for %}?循環渲染列表:

{% extends "base.html" %}{% block title %}用戶列表 - Axum 示例{% endblock %}{% block content %}<h2>用戶列表</h2>{% if users.is_empty() %}<p>暫無用戶</p>{% else %}<ul>{% for user in users %}<li>{{ user.id }}: {{ user.name }} ({{ user.age }} 歲)</li>{% endfor %}</ul>{% endif %}
{% endblock %}

5.4 編寫 Handler 渲染模板

通過?State?提取全局模板環境,傳遞上下文數據(如當前時間、用戶列表),渲染模板并返回 HTML:

use axum::{extract::State, response::Html};
use chrono::Local; // 需要添加依賴:chrono = "0.4.31"
use std::sync::Arc;// 定義用戶結構體(用于傳遞到模板)
#[derive(Debug, serde::Serialize)] // MiniJinja 需要 Serialize  trait
struct User {id: u32,name: String,age: u8,
}// 渲染首頁
async fn render_index(State(state): State<AppState>) -> Html<String> {// 1. 準備上下文數據(需實現 Serialize)let context = minijinja::context! {current_time => Local::now().format("%Y-%m-%d %H:%M:%S").to_string(),username => "alice"};// 2. 加載并渲染模板let template = state.template_env.get_template("index.html").unwrap();let html = template.render(&context).unwrap();Html(html)
}// 渲染用戶列表
async fn render_users(State(state): State<AppState>) -> Html<String> {// 1. 模擬從數據庫獲取用戶數據let users = vec![User { id: 1, name: "Alice".into(), age: 25 },User { id: 2, name: "Bob".into(), age: 30 },User { id: 3, name: "Charlie".into(), age: 28 },];// 2. 傳遞上下文let context = minijinja::context! { users => users };// 3. 渲染模板let template = state.template_env.get_template("users.html").unwrap();let html = template.render(&context).unwrap();Html(html)
}

注意:需添加?chrono?依賴(用于時間格式化)和?serde?依賴(serde = { version = "1.0.193", features = ["derive"] }),因為 MiniJinja 要求上下文數據實現?serde::Serialize

5.5 模板預編譯(生產環境優化)

模板默認是運行時加載,生產環境可預編譯模板到二進制中,避免文件 IO 開銷:

// 預編譯模板(在 init_template_env 中)
fn init_template_env() -> Environment<'static> {let mut env = Environment::new();// 預編譯 base.htmlenv.add_template("base.html", include_str!("../templates/base.html")).expect("Failed to compile base.html");// 預編譯 index.htmlenv.add_template("index.html", include_str!("../templates/index.html")).expect("Failed to compile index.html");// 預編譯 users.htmlenv.add_template("users.html", include_str!("../templates/users.html")).expect("Failed to compile users.html");env.add_filter("upper", |s: &str| s.to_uppercase());env
}

說明:include_str!?是 Rust 宏,編譯時將文件內容嵌入二進制,運行時無需讀取本地文件。


六、綜合示例:完整應用

將上述所有功能整合,最終的?main.rs?如下:

use axum::{extract::State,http::StatusCode,response::{Html, IntoResponse, Redirect},Router, Server,
};
use chrono::Local;
use minijinja::{context::Context, Environment};
use serde::Serialize;
use std::sync::Arc;
use tower_http::{cache_control::{CacheControl, CacheControlLayer},compression::CompressionLayer,cors::{Any, CorsLayer},request_body_limit::RequestBodyLimitLayer,serve_dir::ServeDir,trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer},
};
use tracing_subscriber::{prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt};// 全局狀態
#[derive(Clone)]
struct AppState {template_env: Arc<Environment<'static>>,
}// 用戶結構體
#[derive(Debug, Serialize)]
struct User {id: u32,name: String,age: u8,
}// 初始化模板環境
fn init_template_env() -> Environment<'static> {let mut env = Environment::new();// 預編譯模板env.add_template("base.html", include_str!("../templates/base.html")).expect("Failed to compile base.html");env.add_template("index.html", include_str!("../templates/index.html")).expect("Failed to compile index.html");env.add_template("users.html", include_str!("../templates/users.html")).expect("Failed to compile users.html");// 自定義過濾器env.add_filter("upper", |s: &str| s.to_uppercase());env
}// 404 處理
async fn not_found() -> impl IntoResponse {(StatusCode::NOT_FOUND,Html("<h1>404 - 頁面不存在</h1><p>請檢查路徑是否正確</p>"),)
}// 渲染首頁
async fn render_index(State(state): State<AppState>) -> Html<String> {let context = context! {current_time => Local::now().format("%Y-%m-%d %H:%M:%S").to_string(),username => "alice"};let template = state.template_env.get_template("index.html").unwrap();let html = template.render(&context).unwrap();Html(html)
}// 渲染用戶列表
async fn render_users(State(state): State<AppState>) -> Html<String> {let users = vec![User { id: 1, name: "Alice".into(), age: 25 },User { id: 2, name: "Bob".into(), age: 30 },User { id: 3, name: "Charlie".into(), age: 28 },];let context = context! { users => users };let template = state.template_env.get_template("users.html").unwrap();let html = template.render(&context).unwrap();Html(html)
}#[tokio::main]
async fn main() {// 初始化日志tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| "axum_demo=debug,tower_http=debug".into()),).with(tracing_subscriber::fmt::layer()).init();// 初始化模板環境和全局狀態let template_env = Arc::new(init_template_env());let app_state = AppState { template_env };// 構建路由let app_router = Router::new()// 動態路由(模板渲染).route("/", axum::routing::get(render_index)).route("/users", axum::routing::get(render_users))// 靜態路由(文件服務).nest_service("/static",ServeDir::new("static").not_found_service(axum::routing::get(not_found)),)// 404 處理.fallback(not_found)// 傳遞全局狀態.with_state(app_state);// 疊加 Layerlet app = app_router// 1. 日志追蹤.layer(TraceLayer::new_for_http().make_span_with(DefaultMakeSpan::new().include_headers(true)).on_response(DefaultOnResponse::new().include_headers(true)),)// 2. 跨域.layer(CorsLayer::new().allow_origin(Any).allow_methods(Any).allow_headers(Any),)// 3. 請求大小限制(10MB).layer(RequestBodyLimitLayer::new(10 * 1024 * 1024))// 4. 壓縮.layer(CompressionLayer::new().br(true).gzip(true))// 5. 靜態文件緩存(1 小時).layer(CacheControlLayer::new().with_cache_control(CacheControl::new().max_age(std::time::Duration::from_secs(3600))).on_route(|route| route.starts_with("/static/")),);// 啟動服務Server::bind(&([127, 0, 0, 1], 3000).into()).serve(app.into_make_service()).await.expect("Failed to start server");
}

七、生產環境注意事項

  1. Layer 順序優化

    • 安全相關 Layer(CORS、請求大小限制)放外層,避免無效處理。
    • 日志 Layer 放最外層,記錄完整請求 / 應答。
    • 壓縮 Layer 放內層,減少數據傳輸量。
  2. 靜態文件安全

    • 禁用目錄列表(ServeDir?默認禁用,勿開啟)。
    • 限制靜態文件類型(如僅允許?text/*image/*)。
  3. 模板安全

    • 禁用 MiniJinja 的?eval?和?exec?功能(默認禁用),防止注入攻擊。
    • 對用戶輸入的內容使用?{{ user_input | escape }}?轉義(MiniJinja 默認轉義 HTML)。
  4. 性能優化

    • 預編譯模板到二進制。
    • 為靜態文件添加緩存頭。
    • 使用?tokio?的?release?模式編譯(cargo build --release)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96142.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96142.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96142.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Golang語言設計理念

起源 Golang語言始于2007年&#xff0c;是一門編譯型、靜態類型、并發友好 的語言&#xff0c;由Robert Griesemer&#xff08; 羅伯特格里森、圖靈獎獲得者、C 語法聯合發明人、Unix 之父&#xff09;、Rob Pike&#xff08; 羅布派克、Plan 9 操作系統領導者、UTF-8 編碼的最…

深入掌握 nsenter:Linux命名空間操作的利器

#作者&#xff1a;朱雷 文章目錄1、簡介2、功能與用途2.1. 核心功能2.1.1. 進入命名空間2.1.2. 支持多種命名空間2.1.3. 容器調試3、安裝3.1. 依賴包3.2. 權限要求3.3. 命令用法與示例3.3.1. 基本語法3.3.2. 常用選項包括&#xff1a;3.3.3. 示例4、 應用場景與優勢4.1. 容器調…

Ubuntu Qt x64平臺搭建 arm64 編譯套件

環境&#xff1a; 主機平臺&#xff1a;Ubuntu22.04.5 x86_64 目標平臺&#xff1a;IMX8QM Ubuntu22.04.5 arm64 Qt版本&#xff1a;Qt6.5.3 LST GUI實現&#xff1a;QML 一、獲取Ubuntu22.04.5 x86_64 系統鏡像文件 1、鏡像下載與安裝 使用國內鏡像下載對應版本的Ubuntu鏡像…

mysql第五天學習 Mysql全局優化總結

Mysql全局優化總結 從上圖可以看出SQL及索引的優化效果是最好的&#xff0c;而且成本最低&#xff0c;所以工作中我們要在這塊花更多時間。 補充一點配置文件my.ini或my.cnf的全局參數&#xff1a; 假設服務器配置為&#xff1a; CPU&#xff1a;32核內存&#xff1a;64GDISK…

leetcode hot100 二叉搜索樹

二叉搜索樹的第k小的數class Solution:def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:# 二叉搜索樹的中序遍歷是 升序排列的&#xff0c; 求第k小的&#xff0c;即第k個數self.res []def fun(root):if not root:returnfun(root.left)if root:self.res.a…

從Sonnet到Opus:一次解決RAG知識庫流式輸出難題的探索

又到周末&#xff0c;還得消耗消耗 ?? anyrouter 上的Claude資源&#xff0c;萬一哪天都不能用了&#xff0c;也是浪費。 2025/9/5&#xff0c;Claude AI 的母公司 Anthropic 發布了一項新政策&#xff1a;即日起&#xff0c;Anthropic將不再對中國控股公司及其海外子公司開放…

「數據獲取」中國科技統計年鑒(1991-2024)Excel

02、數據詳情數據名稱&#xff1a;《中國科技統計年鑒》&#xff08;1991-2024年&#xff09;數據年份&#xff1a;1991-202403、數據截圖 04、獲取方式&#xff08;獲取方式看綁定的資源&#xff09;

SimLingo:純視覺框架下的自動駕駛視覺 - 語言 - 動作融合模型

摘要 本文深入探討了 SimLingo&#xff0c;一個在自動駕駛領域具有開創性意義的視覺-語言-動作一體化模型。SimLingo 創新性地將自動駕駛、語言理解和指令感知控制整合到一個統一的純攝像頭框架中&#xff0c;顯著提升了自動駕駛系統在復雜環境中的感知、決策與執行能力。該模…

第五十四天(SQL注入數據類型參數格式JSONXML編碼加密符號閉合復盤報告)

#SQL注入產生原理&#xff1a; 代碼中執行的SQL語句存在可控變量導致 #常見SQL注入的利用過程&#xff1a; 1、判斷數據庫類型 2、判斷參數類型及格式 3、判斷數據格式及提交 4、判斷數據回顯及防護 5、獲取數據庫名&#xff0c;表名&#xff0c;列名 5、獲取對應數據及…

VMWare上搭建Hive集群

文章目錄1. MySQL安裝2. 安裝Hive集群3. 使用Hive客戶端4. 實戰總結本實戰在VMware上搭建Hive集群&#xff0c;集成MySQL作為元數據存儲&#xff0c;完成Hive環境配置、元數據初始化及HDFS倉庫目錄創建&#xff0c;實現Hive on Hadoop的SQL查詢能力&#xff0c;為大數據分析提供…

Android網絡之WIFI技術網絡模型概述

文章目錄術語1、WLAN與WIFI2、802.11 WIFI無線網絡標準演進3、WIFI5、WIFI6和WIFI7的最高速率對比4、WIFI網絡中的各個角色&#xff08;元件&#xff09;1&#xff09;網絡拓撲架構圖5、802.11權威指南1&#xff09;OSI與TCP/IP2&#xff09;IEEE 802.11協議簇介紹3&#xff09…

游戲中的設計模式——第三篇 簡單工廠模式

5. 簡單工廠模式 5.1 簡單工廠模式的定義 簡單工廠模式的核心是定義一個創建對象的接口&#xff0c;將對象的創建和本身的業務邏輯分離&#xff0c;降低系統的耦合度&#xff0c;使得兩個修改起來相對容易些&#xff0c;當以后實現改變時&#xff0c;只需要修改工廠類即可。 5.…

基于SVN搭建企業內部知識庫系統實踐

一、準備工作 CentOS 7 服務器&#xff1a;確保你有 root 或 sudo 權限&#xff0c;可以訪問該服務器。Windows 客戶端&#xff1a;你將需要在 Windows 上安裝 TortoiseSVN 客戶端來與 SVN 服務器交互。防火墻&#xff1a;確保你的防火墻已開放 3690 端口&#xff0c;用于 SVN…

SQL注入7----(盲注與回顯)

一.前言 在我們的注入語句被帶入數據庫查詢但卻什么都沒有返回的情況我們該怎么辦&#xff1f;例如應用程序就會返回 一個"通用的"的頁面&#xff0c;或者重定向一個通用頁面&#xff08;可能為網站首頁&#xff09;。這時&#xff0c;我們之前學習的SQL注入辦 法就…

尚硅谷宋紅康JVM全套教程(詳解java虛擬機)

https://www.bilibili.com/opus/1071553679925968898 案例7&#xff1a;日均百萬訂單系統JVM參數設置 https://github.com/wei198621/jvm_by_atguigu https://github.com/xftxyz2001/atguigu-jvm/blob/main/JavaYouthdocsJVM/%E7%AC%AC1%E7%AB%A0-JVM%E4%B8%8EJava%E4%BD%…

鴻蒙NEXT開發實戰:圖片顯示、幾何圖形與自定義繪制詳解

探索HarmonyOS NEXT強大的圖形渲染能力&#xff0c;從圖片展示到自定義繪圖 HarmonyOS NEXT作為華為自主研發的操作系統&#xff0c;為開發者提供了一套豐富而強大的圖形渲染能力。無論是顯示圖片、繪制幾何圖形&#xff0c;還是實現復雜的自定義繪圖&#xff0c;鴻蒙都提供了簡…

python + Flask模塊學習 2 接收用戶請求并返回json數據

用到的模塊還是flask&#xff0c;用到的類有Flask&#xff0c; request&#xff0c; jsonfiy &#x1f642; 目錄 1、GET請求 2、POST請求 1、表單格式 2、json格式 就醬&#xff0c;也比較簡單&#xff0c;下一篇說簡單的授權&#xff0c;簡單來說就是比如用戶付費買了服…

國內外常用的免費BUG管理工具選型

幫助用戶根據自身情況做決定&#xff0c;比如團隊規模、技術能力、是否需要移動端支持等。避免只是羅列工具&#xff0c;而是提供實際選擇的維度。 國內外常用的免費BUG管理工具選擇非常豐富&#xff0c;從輕量級到功能全面型都有覆蓋。我將它們分為幾類&#xff0c;并詳細介紹…

JavaScript的事件循環機制

1.事件循環的理解JavaScript是單線程的&#xff0c;意味著它一次只能執行一個任務。而事件循環就是去協調在JavaScript環境中運行的同步任務、異步任務(微任務、宏任務)的執行順序的一種機制。它是 JavaScript 實現單線程非阻塞異步執行的核心。2.事件循環的執行順序同步任務—…

數據結構——棧(Java)

目錄 一定義. 入棧 出棧 二.棧與線性表的關系 三.棧的實現方式 四.鏈表實現棧 1.結點的API設計 2.棧的API設計 2.1棧的初始化設計 2.2元素入棧 2.3元素出棧 五.括號匹配問題 完整代碼展示 答案 一定義. 棧是一種基于先進后出&#xff08;FILO&#xff09;的數據…