news 2026/10/14 1:18:31

ntfy自托管通知服务:用curl发送跨平台实时推送

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ntfy自托管通知服务:用curl发送跨平台实时推送

简介:这是一套基于Go语言开发的轻量级跨平台推送通知工具ntfy的完整源码资源,面向开发者、运维工程师及自动化场景实践者,解决多端(手机/桌面)实时消息触达难题,适用于告警系统集成、CI/CD状态通知、IoT设备提醒等典型场景。资源包共415个文件,涵盖106个Go核心逻辑文件、70个PNG与29个JPG图标资源、37个JSON/YAML配置及API定义文件、28个JS/JSX前端交互脚本,以及Dockerfile系列构建文件、各类配置模板(.gitignore、.eslintrc等)和许可证文档,结构完整,开箱即支持本地部署与二次开发。压缩包大小为12.89MB,体积精简但功能完备。目前已有1684人学习下载,读者可直接获取可运行的全栈通知服务源码、标准化容器化部署方案、前后端分离的工程组织范式,以及覆盖移动端PWA、桌面通知、音频提示(MP3/OGG)、WebM/MP4动效图标等多模态通知能力的实现细节。

1. ntfy 是什么:一个能用 curl 发送桌面/手机通知的轻量级自托管服务,不是插件也不是客户端软件

你有没有过这种场景:写完一个耗时 20 分钟的模型训练脚本,想让它跑完自动弹窗提醒你;或者某台服务器上的日志监控脚本检测到异常,需要立刻在手机上收到一条可点击跳转的通知——但又不想接入微信机器人、Telegram Bot 这类带账号体系和隐私风险的第三方通道?ntfy 就是为此而生的:它本质是一个极简的 HTTP 通知中继服务,服务端(server)可单二进制部署,客户端(client)压根不需要安装——你用curl、wget、甚至浏览器地址栏就能发通知;接收端只要打开网页或装个原生 App(iOS/Android),就能实时收到带标题、消息体、点击动作、甚至附件图标的推送。它不依赖云厂商、不绑定手机号、不收集设备指纹,所有通信走标准 HTTP/HTTPS + WebSocket,整个服务启动后仅占用 15MB 内存。适合 DevOps 自动化告警、本地开发流程串联、树莓派状态广播等「小而确定」的推送场景。如果你正在找一个比邮件更及时、比 Slack 更轻、比系统自带 notify-send 更跨平台的方案,ntfy 不是“又一个通知工具”,而是目前唯一能把「发通知」这件事降维成一条 shell 命令的成熟实现。


2. 部署 ntfy server:从零启动一个可公网访问的推送服务(含 TLS 和基础鉴权)

ntfy 的核心优势在于「服务端极简」:它不依赖数据库、不依赖 Redis、不依赖任何外部组件,所有状态默认存在内存里(也可选配 SQLite 或 BoltDB 持久化)。这意味着你不需要 Docker Compose 编排、不需要 k8s YAML、甚至不需要 systemd 服务文件——一个二进制 + 一行命令就能跑起来。但生产环境必须考虑两件事:一是 HTTPS(否则浏览器端无法建立 WebSocket 连接),二是基础访问控制(避免被恶意刷爆)。下面以 Linux x86_64 环境为例,完整走一遍可落地的部署链路。

2.1 下载与验证二进制文件(推荐官方 Release)

ntfy 官方提供预编译二进制,覆盖主流平台。我们优先使用curl直接下载并校验 SHA256(这是防止中间人篡改的关键一步,很多教程会跳过):

# 创建专用目录 mkdir -p ~/ntfy-server && cd ~/ntfy-server # 下载最新稳定版(截至 2024 年中,v2.12.x 是主流) curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.12.3/ntfy_2.12.3_linux_amd64.tar.gz -o ntfy.tar.gz # 下载对应 SHA256 校验文件(注意:不是 .sha256 后缀,而是 .sha256sum) curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.12.3/ntfy_2.12.3_linux_amd64.tar.gz.sha256sum -o ntfy.sha256sum # 校验(输出应为 "OK") sha256sum -c ntfy.sha256sum --ignore-missing

提示:--ignore-missing是为了兼容某些发行版sha256sum对空行的严格处理。若校验失败,请立即停止后续操作——说明下载源可能被污染。

2.2 解压并初始化配置目录

ntfy 默认读取~/.config/ntfy/server.yml,但为便于管理,我们显式指定配置路径,并创建结构清晰的目录:

# 解压(会生成 ntfy 二进制文件) tar -xzf ntfy.tar.gz # 创建配置目录及数据目录 mkdir -p config data # 初始化最小可用配置(server.yml) cat > config/server.yml << 'EOF' # 服务监听地址:0.0.0.0 表示接受所有网卡请求 http-addr: "0.0.0.0:80" https-addr: "0.0.0.0:443" # TLS 证书路径(必须由你提供,下节详述) https-cert-file: "/home/$(whoami)/ntfy-server/config/cert.pem" https-key-file: "/home/$(whoami)/ntfy-server/config/key.pem" # 数据存储路径(SQLite 模式,支持多用户+消息持久化) db-type: sqlite db-file: "/home/$(whoami)/ntfy-server/data/ntfy.db" # 基础认证:启用 token 认证(非用户名密码) auth-default-access: deny auth-default-publish: deny auth-default-admin: false # 允许的 topic 列表(白名单机制,防暴力遍历) allowed-topics: - "dev-alerts" - "sys-monitor" - "ci-finished" EOF

这段配置的关键点在于:

  • http-addr和https-addr必须同时设置,因为现代浏览器强制要求 HTTPS 上的 WebSocket;
  • db-type: sqlite是生产推荐模式,相比默认内存模式,它支持用户管理、消息历史回溯、topic 权限分级;
  • allowed-topics是安全底线:它禁止任意 topic 创建,所有推送必须命中白名单,否则返回 403 —— 这是防止被用作垃圾通知放大器的核心防线。

2.3 获取并配置 TLS 证书(Nginx 反代 or Let's Encrypt 直连)

ntfy 本身不内置 ACME 客户端,所以证书需外部提供。两种主流做法:

方案 A(推荐新手):用 Nginx 反向代理 + Let's Encrypt(certbot)
优点:复用现有 Web 服务器,证书自动续期,ntfy 专注业务逻辑。
步骤简述:

  1. 安装 Nginx 和 certbot;
  2. 配置 Nginx 将https://notify.yourdomain.com的/和/ws路径反代至http://127.0.0.1:80;
  3. 运行certbot --nginx -d notify.yourdomain.com获取证书;
  4. 修改server.yml中https-*字段指向 Nginx 的证书路径(实际 ntfy 不启用 HTTPS,只用 HTTP);
  5. 启动 ntfy 时关闭https-addr,只留http-addr: "127.0.0.1:80"。

方案 B(纯 ntfy):直接使用 Let's Encrypt 证书文件
适用于无 Nginx 场景(如树莓派、VPS 单服务)。需手动获取证书:

# 使用 certbot standalone 模式(需确保 80/443 端口空闲) sudo certbot certonly --standalone -d notify.yourdomain.com # 软链接到 ntfy 配置路径(避免权限问题) sudo ln -sf /etc/letsencrypt/live/notify.yourdomain.com/fullchain.pem config/cert.pem sudo ln -sf /etc/letsencrypt/live/notify.yourdomain.com/privkey.pem config/key.pem

注意:cert.pem必须是fullchain.pem(含中间证书),不能只用cert.pem,否则 iOS 客户端会握手失败。

2.4 启动服务并验证基础连通性

配置就绪后,用以下命令启动(加-d后台运行,-c指定配置):

# 启动(日志输出到 stdout,方便调试) ./ntfy serve -c ./config/server.yml # 或后台运行(生产环境) nohup ./ntfy serve -c ./config/server.yml > ntfy.log 2>&1 &

验证是否启动成功:

  • 访问http://your-server-ip:80→ 应看到 ntfy 的 Web UI(主题列表页);
  • 访问https://your-domain.com(若已配 HTTPS)→ 同样显示 UI,且浏览器地址栏有锁图标;
  • 执行curl -I https://your-domain.com→ 响应头中应含Server: ntfy。

此时服务已就绪,但还不能收通知——因为没创建 topic,也没配置接收端。下一步就是让通知真正“抵达”。


3. 接收端配置:Web 页面订阅、Android/iOS 原生 App、以及桌面端静默集成

ntfy 的接收能力分三层:最轻量的是 Web 浏览器(无需安装),其次是官方原生移动 App(功能最全),最后是桌面端(Linux/macOS/Windows)通过系统通知 API 集成。三者共用同一套 topic 订阅机制,但权限模型和体验细节差异极大。下面按落地优先级展开。

3.1 Web 端:用浏览器完成首次订阅(零安装、即时生效)

这是最快验证服务是否工作的路径。打开https://your-domain.com(或http://ip:80),页面顶部搜索框输入你配置的白名单 topic(如dev-alerts),点击「Subscribe」按钮。此时浏览器会弹出「是否允许通知」提示,点击「允许」。

关键行为验证:

  • 在 Web UI 页面右上角点击「Send test notification」,应立刻在浏览器右下角弹出系统通知(标题为「Test notification」);
  • 打开浏览器开发者工具(F12)→ Application → Service Workers,确认sw.js已注册且状态为activated;
  • 切换到 Network 标签,刷新页面,观察到https://your-domain.com/ws/dev-alerts连接状态为WebSocket,Status 为101 Switching Protocols。

提示:Web 端通知依赖浏览器的 Service Worker,因此必须通过 HTTPS(或 localhost)访问。HTTP 下只能收一次,刷新即失效。

3.2 Android/iOS 原生 App:离线可靠、支持点击跳转与附件

官方 App(Google Play / App Store 搜索 “ntfy”)是生产环境首选,原因有三:

  1. 离线保活强:利用系统级推送通道(Android FCM / iOS APNs),即使 App 被杀后台,通知仍可达;
  2. 交互丰富:支持设置点击动作(如打开 URL、复制文本)、添加图标、设置优先级;
  3. 权限精细:可为每个 topic 单独开关通知、声音、震动。

配置步骤(以 Android 为例):

  1. 安装 App 后,点击「Add server」→ 输入你的域名(https://notify.yourdomain.com);
  2. 点击「Add topic」→ 输入dev-alerts(必须与 server.yml 白名单一致);
  3. 进入 topic 设置页 → 开启「Notifications」、「Sound」、「Vibrate」;
  4. 在「Actions」中添加一个「Open URL」动作,URL 填https://your-ci-dashboard.com/build/last(示例)。

此时,任何向该 topic 发送的通知,都会触发手机端完整通知栏条目,点击即可跳转。

注意:iOS 用户首次添加 server 时,App 会提示「Allow notifications」,必须手动开启,否则收不到。这是系统级限制,ntfy 无法绕过。

3.3 桌面端:Linux/macOS/Windows 通过 ntfy CLI 或 D-Bus/NotificationCenter 集成

桌面端分两种集成方式:

  • CLI 方式:用ntfy subscribe命令在终端监听 topic,配合notify-send(Linux)或osascript(macOS)转发为系统通知;
  • 原生集成:Linux 下通过 D-Bus 直连,macOS 用 Notification Center API,Windows 用 Toast Notification。

我们以 Linux(GNOME/KDE)为例,实现「终端监听 + 图形界面弹窗」闭环:

# 安装 ntfy CLI(与 server 同版本) curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.12.3/ntfy_2.12.3_linux_amd64.tar.gz | tar -xzf - ntfy sudo install ntfy /usr/local/bin/ # 创建监听脚本(~/bin/ntfy-listen.sh) cat > ~/bin/ntfy-listen.sh << 'EOF' #!/bin/bash ntfy subscribe --server https://notify.yourdomain.com dev-alerts | \ while IFS= read -r line; do # 解析 JSON(ntfy CLI 输出为 JSON Lines) if echo "$line" | jq -e '.id' >/dev/null 2>&1; then TITLE=$(echo "$line" | jq -r '.title // "ntfy"') MESSAGE=$(echo "$line" | jq -r '.message // "No message"') # 调用 GNOME 系统通知 notify-send -u normal -a "ntfy" "$TITLE" "$MESSAGE" fi done EOF chmod +x ~/bin/ntfy-listen.sh # 后台运行(开机自启可加到 ~/.profile) ~/bin/ntfy-listen.sh &

此脚本的关键在于:

  • ntfy subscribe是长连接命令,会持续输出 JSON Lines 格式消息;
  • jq解析确保只处理有效通知体(跳过 ping/pong 心跳包);
  • notify-send是 GNOME 标准命令,KDE 用户可替换为kdialog --passivepopup。

血泪经验:不要用&直接后台运行ntfy subscribe,它会因终端退出而中断。务必用nohup或 systemd user service 包裹。


4. 发送通知:curl 是主力,但不同场景要选对参数和方法

ntfy 的发送接口设计极度克制:只有一个 POST endpoint/,所有定制化都靠 HTTP Header 控制。这带来极高的可编程性,但也意味着——错一个 Header,通知就静默失败。下面按典型场景拆解最常踩坑的参数组合。

4.1 最简发送:一条 curl 命令触发桌面弹窗

这是入门验证的黄金命令,也是自动化脚本的基石:

curl -X POST \ -H "Title: Build Success" \ -H "Priority: high" \ -H "Tags: white_check_mark,rocket" \ -d "CI job finished in 4m23s" \ https://notify.yourdomain.com/dev-alerts

参数解析:

  • TitleHeader:通知标题,不设则默认为 topic 名(dev-alerts);
  • Priority:取值min,low,default,high,urgent,影响通知样式和声音(high以上才触发重复提醒);
  • Tags:逗号分隔的 Emoji 别名,ntfy 会自动转为 Unicode(white_check_mark→ ✅,rocket→ 🚀);
  • 请求体(-d):通知正文,纯文本,最大 10KB。

提示:Priority: urgent在移动端会触发强震动+红点角标,但桌面端无额外效果,需结合ActionsHeader 使用。

4.2 进阶发送:带点击动作、附件、延迟送达的完整通知

当通知需要引导用户执行操作时,必须用ActionsHeader 构造按钮。格式为actionType:label:URL,支持多个动作(用;分隔):

curl -X POST \ -H "Title: Deployment Ready" \ -H "Priority: urgent" \ -H "Tags: package,cloud" \ -H "Actions: view:View Logs:https://logs.yourapp.com/deploy-123; copy:Copy ID:copy:deploy-123" \ -H "Click: https://dashboard.yourapp.com/release/v2.1" \ -d "v2.1 deployed to production. Rollback window: 30min." \ https://notify.yourdomain.com/dev-alerts

关键 Header 说明:

  • Actions:view类型打开 URL,copy类型复制文本到剪贴板(copy:xxx语法);
  • Click:整个通知区域的点击跳转 URL(与第一个view动作互斥,建议只用其一);
  • 若需发送图片附件,Header 加Attach: https://img.yourcdn.com/screenshot.png,但注意:附件 URL 必须支持 CORS,且 ntfy server 会主动 GET 下载并缓存(需确保attach-cache-dir配置充足空间)。

4.3 安全发送:Token 认证与 IP 白名单双保险

默认部署下,ntfy 允许任意 IP 向白名单 topic 发送通知,这在内网可行,公网需加固。两种方式:

方式一:Token 认证(推荐)
在server.yml中启用:

auth-default-access: deny auth-default-publish: deny auth-tokens: - id: "ci-server" key: "sk_xxx_your_secret_key" # 32位随机字符串 access: ["dev-alerts"] publish: ["dev-alerts"]

发送时加 Header:

curl -H "X-NTFY-KEY: sk_xxx_your_secret_key" \ -d "Build passed" \ https://notify.yourdomain.com/dev-alerts

方式二:IP 白名单(适合固定出口 IP)
在server.yml中:

auth-ip-whitelist: - "192.168.1.100/32" # CI 服务器 - "203.0.113.50/32" # 运维笔记本

此时无需 Token,但 IP 不在列表内则直接 403。

注意:Token 和 IP 白名单可叠加使用,但auth-ip-whitelist优先级更高——若 IP 不在白名单,Token 无效。


5. 避坑 / 常见问题 / 排查:五条真实翻车记录与解法

ntfy 文档简洁,但生产环境总有文档没写的边界情况。以下是我在三个不同项目中踩过的坑,按发生频率排序,每条附可复现现象和根因定位法。

5.1 现象:Web 页面能收通知,但 Android App 一直显示「Connecting…」

原因:服务器未正确配置 HTTPS,或证书链不完整(cert.pem缺少中间证书)。iOS 对证书校验更宽松,Android(尤其较新版本)会严格拒绝。
解决:

  1. 用openssl s_client -connect your-domain.com:443 -servername your-domain.com检查Verify return code是否为0 (ok);
  2. 若返回21 (unable to verify the first certificate),说明证书链缺失,需用fullchain.pem替换cert.pem;
  3. 在 Android App 的 server 设置页,点击「Test connection」看具体错误码(常见ERR_SSL_VERSION_OR_CIPHER_MISMATCH)。

5.2 现象:curl发送成功(返回 200),但所有接收端都收不到

原因:allowed-topics配置未生效,或 topic 名拼写大小写不一致(ntfy topic 区分大小写)。
解决:

  1. 检查server.yml中allowed-topics是否包含你发送的 topic(如Dev-Alerts≠dev-alerts);
  2. 查看 ntfy 日志(启动时 stdout 或ntfy.log),搜索topic not allowed关键字;
  3. 临时将allowed-topics改为["*"]测试,若恢复则确认是白名单问题。

5.3 现象:通知送达延迟 10~30 秒,尤其在低活跃度 topic

原因:ntfy 默认启用「批量合并」优化:当同一 topic 短时间内收到多条通知,会合并为一条(带计数),避免通知风暴。
解决:

  1. 在发送请求中加 HeaderX-NTFY-Disable-Batching: true强制禁用;
  2. 或修改server.yml全局关闭:batching-enabled: false;
  3. 验证:发送两条间隔 1 秒的通知,观察接收端时间戳是否精确匹配。

5.4 现象:Linux 桌面端notify-send不弹窗,但终端输出正常

原因:D-Bus session bus 未正确继承。当ntfy-listen.sh由 systemd user service 或 cron 启动时,$DBUS_SESSION_BUS_ADDRESS环境变量为空。
解决:

  1. 在脚本开头添加:export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus";
  2. 或改用systemd --user import-environment DBUS_SESSION_BUS_ADDRESS启动;
  3. 测试:手动执行notify-send "test",若失败则先修复 D-Bus 环境。

5.5 现象:iOS App 收不到通知,但 Web 和 Android 正常

原因:APNs 证书过期,或 ntfy server 未正确配置apns-topic(iOS App Bundle ID)。
解决:

  1. 登录 Apple Developer Portal,检查Key或Certificate是否过期;
  2. 在server.yml中确认apns-topic: "com.example.ntfy"与 App 的 Bundle ID 一致;
  3. iOS 端进入 App 设置 → 通知 → 确认「允许通知」已开启,且「锁定屏幕」、「通知中心」、「横幅」均勾选。

6. 进阶技巧:用 ntfy 实现「CI/CD 流水线状态机」与消息审计追踪

ntfy 的真正威力不在单点通知,而在于它能把异步事件流变成可观测的状态机。我曾在某跨平台系统 CI 流程中,用 ntfy 构建了一套零侵入、可审计、带上下文追溯的通知体系。核心思路是:每个构建任务生成唯一 ID 作为 topic 后缀,用 HTTP Status Code 控制通知语义,再用 SQLite 数据库做消息溯源。下面给出可直接复用的模板。

6.1 构建 Topic 命名规范:用流水线 ID 绑定上下文

避免所有通知挤在ci-finished这种泛 topic 下。改为动态生成 topic,格式为ci-{pipeline_id}-{build_number}。例如:

  • ci-webapp-12345:前端项目第 12345 次构建;
  • ci-android-789:安卓 App 第 789 次构建。

好处:

  • Web UI 可按 topic 过滤,快速定位某次构建全过程;
  • 移动端可为高频 topic 单独设置静音(如ci-android-*夜间不响);
  • SQLite 数据库中messages.topic字段天然形成索引,查某次构建的所有通知只需SELECT * FROM messages WHERE topic = 'ci-webapp-12345'。

6.2 用 HTTP Status Code 表达状态语义(替代 Priority)

ntfy 允许在发送时返回自定义 HTTP 状态码(需 server.yml 配置http-status-codes: true),我们将其映射为 CI 状态:

Status语义Actions 示例
200成功view:View Report:https://ci/report/12345; copy:Copy Artifacts:copy:artifacts-12345
400参数错误view:Fix Config:https://git/config.yaml
500构建失败view:View Logs:https://ci/logs/12345; retry:Retry Build:https://ci/retry/12345

发送脚本片段(Jenkins Pipeline):

// Jenkinsfile 中 def buildId = env.BUILD_ID def topic = "ci-webapp-${buildId}" // 构建成功 sh "curl -X POST -H 'Title: ✅ Build ${buildId} Success' -H 'Actions: view:Report:https://ci/report/${buildId}' -d 'Deployed to staging' https://notify.yourdomain.com/${topic}" // 构建失败(返回 500 触发重试按钮) sh "curl -X POST -H 'Title: ❌ Build ${buildId} Failed' -H 'Actions: view:Logs:https://ci/logs/${buildId}; retry:Retry:https://ci/retry/${buildId}' -d 'Exit code: ${env.BUILD_RESULT}' -w '%{http_code}' https://notify.yourdomain.com/${topic}"

6.3 消息审计:从 SQLite 数据库提取完整构建轨迹

ntfy 的 SQLite 模式会将每条通知存入messages表,字段包括id,topic,time,title,message,priority,tags。我们可编写审计脚本,生成某次构建的完整时间线:

-- 查询 ci-webapp-12345 的所有通知,按时间排序 SELECT datetime(time, 'unixepoch', 'localtime') as timestamp, title, message, priority, tags FROM messages WHERE topic = 'ci-webapp-12345' ORDER BY time ASC;

结果示例:

2024-06-15 14:22:03 | 🚀 Build 12345 Started | Checkout code from main | default | rocket 2024-06-15 14:25:18 | ✅ Lint Passed | No errors found | high | white_check_mark 2024-06-15 14:28:42 | ✅ Tests Passed | 124/124 passed | high | white_check_mark 2024-06-15 14:31:05 | 🌐 Deployed to Staging | URL: https://staging.example.com | urgent | globe_with_meridians

这份输出可直接粘贴进 Confluence 作为构建报告,或用sqlite3命令行导出 CSV 供 BI 工具分析。

从那以后我每次搭建 CI 流水线,都强制走一遍「topic 命名规范 → Status Code 映射 → SQLite 审计查询」三步。不是为了炫技,而是当凌晨三点报警电话响起时,我能用一条 SQL 精确还原出故障前 5 分钟发生了什么——而不是翻 20 个日志文件。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 1:18:30

Kubernetes 部署 Apollo 配置中心实战:架构、调优与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 1:18:03

SPIFFE+Modbus:工业现场零信任身份网关落地实践与踩坑记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 1:17:58

单相桥式有源逆变Simulink仿真:从原理到波形调试避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 1:17:56

DirectX 12光线追踪实战:DXR加速结构与降噪优化指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 1:17:46

C#线程安全集合深度解析:从ConcurrentDictionary到Channel的选型与避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 1:17:31

MMX在现代x86_64 Linux中的实战价值与调试方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华