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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;的数据…