惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
IT之家
IT之家
S
SegmentFault 最新的问题
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
J
Java Code Geeks
博客园 - 聂微东
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
The Cloudflare Blog
博客园_首页
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 【当耐特】
腾讯CDC
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
宝玉的分享
宝玉的分享
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
月光博客
月光博客
NISL@THU
NISL@THU
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
Blog — PlanetScale
Blog — PlanetScale
aimingoo的专栏
aimingoo的专栏
L
LINUX DO - 热门话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Fortinet All Blogs
博客园 - Franky
L
Lohrmann on Cybersecurity
S
Secure Thoughts
量子位
V
Vulnerabilities – Threatpost
Last Week in AI
Last Week in AI
博客园 - 叶小钗
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LINUX DO - 最新话题
I
InfoQ
C
CERT Recently Published Vulnerability Notes
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Proofpoint News Feed
G
GRAHAM CLULEY
Cisco Talos Blog
Cisco Talos Blog

元视角

.NET 生态下的 Agent 框架选型:从 ReAct 到原生推理 - 元视角 从「能用」到「好用」:LLM 流式响应实现方式的探索之路 - 元视角 当我用 2000 条聊天记录,让 AI 为我画一幅自画像 - 元视角 基于 Supabase 的 AI 应用开发探索 - 元视角 微博 × MCP:社交媒体新玩法解锁 - 元视角 四点钟海棠花未眠 - 元视角 Semantic Kernel × MCP:智能体的上下文增强探索 - 元视角 基于 K-Means 聚类分析实现人脸照片的快速分类 - 元视角 容器技术驱动下的代码沙箱实践与思考 - 元视角 温故而知新:后端通用查询方案的再思考 - 元视角 浅议 CancellationToken 在前后端协同取消场景中的应用 - 元视角 Semantic Kernel 视角下的 Text2SQL 实践与思考 - 元视角 关于 ChatGPT 的流式传输,你需要知道的一切 - 元视角 RAG 的是与非、Rewrite 和 Rerank - 元视角 使用 EFCore 和 PostgreSQL 实现向量存储及检索 - 元视角 基于 LLaMA 和 LangChain 实践本地 AI 知识库 - 元视角 使用 llama.cpp 在本地部署 AI 大模型的一次尝试 - 元视角 如何为 Git 配置多个 SSH Key - 元视角 C# 使用 LibUsbDotNet 实现 USB 设备检测 - 元视角 基于 C# 实现样式与数据分离的打印方案 - 元视角 基于 SVG 的图形交互方案实践 - 元视角 前端视频播放技术概览 - 元视角 温故而知新,再话 Python 动态导入 - 元视角 后 GPT 时代,NLP 不存在了? - 元视角 视频是不能 P 的系列:使用 Milvus 实现海量人脸快速检索 - 元视角 GDI+下字体大小自适应方案初探 - 元视角 小爱音箱集成 ChatGPT 的不完全教程 - 元视角 程序员视角下的三体世界随想 - 元视角 关于 Docker 容器配置信息的渐进式思考 - 元视角 在 Docker 容器内集成 Crontab 定时任务 - 元视角 为你的服务器集成 LDAP 认证 - 元视角 似花还似非花 - 元视角 视频是不能 P 的系列:使用 Dlib 实现人脸识别 - 元视角 浅议分布式链路追踪与日志的整合 - 元视角 关于 Git 大文件上传这件小事 - 元视角 .NET 进程内队列 Channel 的入门与应用 - 元视角 使用 Fody 实现 .NET 的静态编织 - 元视角 .NET Core + ELK 搭建可视化日志分析平台(下) - 元视角 聊一聊前端图片懒加载背后的故事 - 元视角 支持外部链接跳转的 Vue Router 扩展实现 - 元视角 视频是不能 P 的系列:OpenCV 和 Dlib 实现表情包 - 元视角 不得不说的 ASP.NET Core 集成测试 - 元视角 再议 DDD 视角下的 EFCore 与 领域事件 - 元视角 Vue.js 前端项目容器化部署实践极简教程 - 元视角 再见,人间四月天 - 元视角 Python 图像风格化迁移助力画家梦想 - 元视角 利用 ASP.NET Core 中的标头传播实现分布式链路追踪 - 元视角 利用 gRPC 实现文件的上传与下载 - 元视角 七种武器:延迟队列的原理和实现总结 - 元视角 gRPC 流式传输极简入门指南 - 元视角 Envoy 集成 Jaeger 实现分布式链路追踪 - 元视角 浅议非典型 Web 应用场景下的身份认证 - 元视角 gRPC 借助 Any 类型实现接口的泛化调用 - 元视角 分布式丛林探险系列之 Redis 集群模式 - 元视角 分布式丛林探险系列之 Redis 主从复制模式 - 元视角 通过 Python 预测 2021 年双十一交易额 - 元视角 gRPC 搭配 Swagger 实现微服务文档化 - 元视角 SSL/TLS 加密传输与数字证书的前世今生 - 元视角 使用 Python 自动识别防疫健康码 - 元视角 你不可不知的容器编排进阶技巧 - 元视角 ASP.NET Core 搭载 Envoy 实现 gRPC 服务代理 - 元视角 再话 AOP,从简化缓存操作说起 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务身份认证(JWT) - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的监控预警 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的反向代理 - 元视角 ASP.NET Core gRPC 打通前端世界的尝试 - 元视角 EFCore 实体命名约定库:EFCore.NamingConventions - 元视角 ASP.NET Core gRPC 集成 Polly 实现优雅重试 - 元视角 ASP.NET Core gRPC 健康检查的探索与实现 - 元视角 ASP.NET Core gRPC 拦截器的使用技巧分享 - 元视角 SnowNLP 使用自定义语料进行模型训练 - 元视角 使用 HttpMessageHandler 实现 HttpClient 请求管道自定义 - 元视角 ABP vNext 的实体与服务扩展技巧分享 - 元视角 ABP vNext 对接 Ant Design Vue 实现分页查询 - 元视角 源代码探案系列之 .NET Core 跨域中间件 CORS - 元视角 源代码探案系列之 .NET Core 限流中间件 AspNetCoreRateLimit - 元视角 源代码探案系列之 .NET Core 并发限制中间件 ConcurrencyLimiter - 元视角 通过 EmbededFileProvider 实现 Blazor 的静态文件访问 - 元视角 低代码,想说爱你不容易 - 元视角 记一次失败的 ThoughtWorks 面试经历 - 元视角 从 C# 1.0 到 C# 9.0,历代 C# 语言特性一览 - 元视角 通过 Python 分析 2020 年全年微博热搜数据 - 元视角 基于 Python 和 Selenium 实现 CSDN 一键三连自动化 - 元视角 使用多线程为你的 Python 爬虫提速的 N 种姿势,你会几种? - 元视角 实现网页长截图的常见思路总结 - 元视角 温故而知新,由 ADO.NET 与 Dapper 所联想到的 - 元视角 视频是不能 P 的系列:OpenCV 人脸检测 - 元视角 作为技术宅的我,是这样追鬼滅の刃的 - 元视角 使用 Python 抽取《半泽直树》原著小说人物关系 - 元视角 厉害了!打工人用 Python 分析西安市职位信息 - 元视角 使用 dotTrace 对 .NET 应用进行性能分析与优化 - 元视角 一道 HashSet 面试题引发的蝴蝶效应 - 元视角 基于选项模式实现.NET Core 的配置热更新 - 元视角 Dapper.Contrib 在 Oracle 环境下引发 ORA-00928 异常问题的解决 - 元视角 .NET Core 中对象池(Object Pool)的使用 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(下):EventBus 篇 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(中):RabbitMQ 篇 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(上):基础篇 - 元视角 记一次从已损坏的 Git 仓库中找回代码的经历 - 元视角 .NET Core 原生 DI 扩展之属性注入实现 - 元视角
使用 jsDelivr 为 Hexo 博客提供高效免费的CDN加速 - 元视角
飞鸿踏雪 · 2020-02-06 · via 元视角

最近给博客做了升级,从 3.x 升级到了 4.x,主要是在官网看到了关于静态页面生成效率提升的内容。众所周知,Hexo 在文章数目增加以后会越来越慢。博主大概是从 14 年年底开始使用 Hexo 这个静态博客的,截止到目前一共有 176 篇博客,其中的“慢”可想而知,中间甚至动过使用 Hugo 和 VuePress 的念头,所以,听说有性能方面的提升,还是决定第一时间来试试。整个升级过程挺顺利的,唯一遇到的问题是关于外部链接检测方面的,具体可以参考这里。今天,博主主要想和大家分享下关于如何使用jsDelivr来为博客提供免费、高效的 CDN 服务,希望对大家有所帮助。

jsDelivr是一个免费、快速和可信赖的 CDN 加速服务,官网上声称它每个月可以支撑680亿次的请求。博主是在去年年底的时候,偶然了解到这个服务的存在,这次趁着疫情肆虐的间隙,终于把这个服务集成到了博客中。更重要的是,这个服务在 Github 上是开源的。目前,它提供了针对npmGithubWordPress的加速服务,只需要一行代码就可以获得加速效果,以常用的jQuery和Bootstrap为例:

// load jQuery v3.2.1
https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js

// load bootstrap v4.4.1
https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.js

这意味着我们只需要发布一个 npm 的包,就可以使用它提供的加速服务。CDN 加速的好处我这里就不再多说了,只要我们的项目中用到了第三方的静态资源,譬如 JavaScript/CSS 等等都应该考虑接入到 CDN 中。有人常常担心 CDN 挂掉或者是私有化部署无法接入外网环境。我想说,我们目光应该长远一点,现在早已不是早年那种单打独斗式的开发模式了,我们不可能把所有资源都放到本地来。随着云计算的概念越发地深入人心,越来越多的基础服务都运行在一台又一台虚拟化的“云服务器”上,这种情况下,搞这种集中化配置的做法,是完全违背分布式的发展趋势的。

如果说,针对 npm 包的 CDN 加速服务离我们还有点遥远,因为我们大多数情况下都是在使用别人写好的库。那么,接下来,针对 Github 的 CDN 加速服务应该会让我们无比兴奋吧,毕竟 Github Pages 的“慢”大家是可以感受得到的。不然,为什么大家要用 Coding Pages 做国内/国外的双线部署呢?首先,我们在浏览器里输入下面这个地址:https://cdn.jsdelivr.net/gh/qinyuanpei/qinyuanpei.github.io@latest/

jsDelivr提供的CDN加速资源 jsDelivr提供的CDN加速资源

此时,可以注意到,jsDelivr可以把我们 Github 上的资源呈现出来,只要我们在 Github 上发布过相应的版本即可。这里的版本,可以理解为一次 Release,对应 Git 中 tag 的概念,虽然 Github 现在引入了包管理器的概念,试图统一像 npm、nuget、pip 等等这样的包管理器。它提供的 CDN 服务有一个基本的格式:

https://cdn.jsdelivr.net/gh/user/repo@version/file

如果大家感兴趣,可以把这里的 user 和 repo 改成自己的来体验一番。需要注意的是,这里的版本号同样可以换成 Commit ID 或者是分支的名称。我个人建议用 tag,因为它通常携带了版本号信息,语义上要更好一点。那么,顺着这个思路,我们只要把 Hexo 中的资源的相对路径改为 jsDelivr 的 CDN 加速路径就好啦!为了让切换更加自如,这里我们为 Hexo 写一个 Helper,它可以理解为 Hexo 中的辅助代码片段。我们在 <YouTheme>/scripts/ 目录下新建一个plugins.js 文件,这样 Hexo 会在渲染时自动加载这个脚本文件:

const source = (path, cache, ext) => {
    if (cache) {
        const minFile = `${path}${ext === '.js' ? '.min' : ''}${ext}`;
        const jsdelivrCDN = hexo.config.jsdelivr;
        return jsdelivrCDN.enable ? `//${jsdelivrCDN.baseUrl}/gh/${jsdelivrCDN.gh_user}/${jsdelivrCDN.gh_repo}@latest/${minFile}` : `${minFile}?v=${version}`
    } else {
        return path + ext
    }
}
hexo.extend.helper.register('theme_js', (path, cache) => source(path, cache, '.js'))
hexo.extend.helper.register('theme_css', (path, cache) => source(path, cache, '.css'))

接下来,修改布局文件,项目中的 JavaScript 和 CSS 文件,均通过 theme_js()thems_css() 两个函数引入:

//加载JavaScript
<script src="<%- url_for(theme_js('assets/scripts/search', cache)) %>" async></script>
//加载CSS
<link rel="stylesheet" href="<%- url_for(theme_css('/assets/styles/style', cache)) %>">

既然是否使用 CDN 加速是可配置的,我们要在 _config.yml 文件中添加相应的配置项:

# jsdelivr CDN
jsdelivr:
  enable: true
  gh_user: qinyuanpei
  gh_repo: qinyuanpei.github.io
  baseUrl: cdn.jsdelivr.net

除此以外,我们还需要在部署博客的时候,生成一个名为 latest 的 tag。虽然官网上说,在引用 CDN 的时候版本号可以省略,不过经过博主反复尝试,不带版本号并不会指向正确的版本,有些资源文件会报 404,因为这部分资源文件回滚以后发现还是没有。所以,最后博主只好把这个版本号给固定下来了,这样又引入一个新问题,即:每次部署的时候都要先删除远程的 latest。所以,这块儿的Travis CI脚本看起来会有点讨厌,如果大家有更好的方案,欢迎大家在博客中留言:

 git tag latest
 git push --force --quiet "https://${CI_TOKEN}@${GH_REF}" master:master --tags

好了,现在重新生成、部署,来看看效果吧: Coding Pages速度 Coding Pages速度

Github Pages速度 Github Pages速度 感觉效果还不错,Github Pages 比平时要快很多,博主顺便就给 Coding Pages 启用了 CDN 加速。话说,看到这张图的时候总是感慨,如果肺炎疫情地图能像这两张图一样就好啦!面对这场无声的战役,有很多人一直在一线抗击病魔,还有很多人默默无闻地在支援武汉。或许,宅在家里的你我,什么都做不了,可即便如此,还是让我们一起来祈祷疫情快点结束吧,因为春天都要来了呢……好了,这就是这篇博客的全部内容啦,谢谢大家!

2020/02/13 更新

在此之前,博主提到版本号的问题,即每一次在 CDN 上生成的版本,怎样体现到 Hexo 中引用的资源上面。当时采用了一个取巧的方法,Hexo 中固定版本号为 latest,然后每次都推送这个 tag。这样引发一个问题,每次都先去远程删除这个 tag,显然这不是我期望的解决方案。最终,我采用的方案是,通过 Travis CI 编译部署的时候,首先导出变量 $TRAVIS_BUILD_NUMBER 到一个文本文件中,然后Hexo在生成静态页面的时侯,从这个文本文件中读取该变量的值作为版本号,这样每次编译部署的时候,我们总能获得一个新的 tag,而这个 tag 和 Hexo 中引用的资源版本一致,这样就彻底解决了这个遗留问题。修改后的 plugins.js 文件内容如下:

var fs = require('fs');
var version = 'latest'
fs.readFile('./BUILD_NUMBER.txt', function (error, data) {
    if (error) {
      console.log('load BUILD_NUMBER.txt fails, ' + error)
    } else {
        version = data.toString().trim();
    }
});

const source = (path, cache, ext) => {
    if (cache) {
        const minFile = `${path}${ext === '.js' ? '.min' : ''}${ext}`;
        const jsdelivrCDN = hexo.config.jsdelivr;
        return jsdelivrCDN.enable ? `//${jsdelivrCDN.baseUrl}/gh/${jsdelivrCDN.gh_user}/${jsdelivrCDN.gh_repo}@${version}/${minFile}` : `${minFile}?v=${version}`
    } else {
        return path + ext
    }
}
hexo.extend.helper.register('theme_js', (path, cache) => source(path, cache, '.js'))
hexo.extend.helper.register('theme_css', (path, cache) => source(path, cache, '.css'))

修改后的 .travis.yml 文件可以在 这里 获取。