普通视图

发现新文章,点击刷新页面。
昨天以前旅行者的随想

累,也要咬牙坚持

坚持才是最难的

嗯,不知不觉,坚持每天刷多邻国已经 365 天了。

说来惭愧,第一次学习英语能坚持这么长时间。想到高考的英语分数才只有 40 多分,这一年的时间,我基本完成了英语入门。英语一直被我认为是世界上最难学习的东西,没有之一。所以我这几天也想了很多,就从今天开始,整个下半年,大部分的空闲时间都要拿来学英语,我相信自己可以的,所以今天就是 Day 1 了。

资料基本上都买齐了,《薄冰英语语法手册》和《新概念英语 1 》的课本、语法练习以及练习册。准备了 2 个 B5 的本子,一个记录每天学过的单词,一个记录重要的语法和句子。2 个 A7 的小本子,一个用来每天晚上写第二天的学习计划(Todo),一个用来记录每天的学习情况(Summary)。

我做笔记,学完之后做完总结就基本上再也不会去看了。但是这个过程,对我来说是个很重要的思考过程,可以理解为大脑思考在现实世界的一个投影。我学习编程的时候也喜欢这么干,不管是笔记、思维导图、技术分享还是写博客。

为什么要从 0 开始学

其实不管是编程、英语还是数学,在这一类领域中,每个知识点/块之间的依赖性是很大的。这也就意味着学习是有门槛的,虽然丢掉了依赖路径上的一部分,也能学的不错,但是最基础的内容,才是最重要的。只有对哪些被以来的基础领域,掌握了,学习更高阶的领域的时候,才会“往返自然”。

所以这也是我为什么要从新概念英语 1 开始学,我真的想学好。

计划

准备先把统考英语考过,然后拿到专升本的毕业证和学位证。所以今年剩下的时间,就要拼命学习英语了!!!

虽然高考结束,只上了专科,但是我真的不甘心。我不希望我的人生就是这个样子,在学校、在社会上,我都经历了太多嘲笑,但是我觉得这都是应该的,谁叫我自己不努力呢?但如果我自己也选择了摆烂,那这绝不是我想要的人生。

毕业之后,我并没有选择全日制的专升本,因为我觉得自己读书这么没用,不想让家里再花钱供我读书了。所以我花了 8500 块钱,报了个非全日制的专升本,一边升本、一边工作赚钱。顺利的话,明年就能拿到双证了,加油!💪

我不知道我能走多远,也不知道考试都能不能过。但是我想给自己一次机会,我不想年纪大了又后悔。所以明年专升本毕业后,就可以尝试报名考考看了,即使没考上,但是无数个日夜学习的英语、数学以及计算机学科专业基础知识,我想也能帮助我在编程这条路上走得更远吧。工作前两年摸爬滚打,挺多的学习时间全部拿来学习编程了,现在至少工作上的问题,碰到了可以全部解决,也养成了一套自己的学习方法和编程思维。从杭州回武汉也一年了,虽然武汉的工资相对来说不那么高,但是目前的现状还算不错,双休不加班,这些时间都可以被我利用起来。

我是 99 年的,今年 24 了,我还有梦想,我还要走的更远。我也希望能遇到更好的女生,也希望面对女生时不会因为自己差而感到自卑。我也想交更多优秀的朋友但前提是先把自己变优秀了。

就这样吧,大半夜写点东西,希望偶然看到博客的你,也能生活快乐,勇敢去追逐自己的梦想。

如何使用 Cloudflare 保护云服务——扫盲“WAF”及其它招数

前言

五一前后抽时间维护了一下个人云服务,把集群全部重构了一部分。那几天访问的朋友们应该能看到一个简单的“维护页面”。新的个人云架构,这里就不多讲了,毕竟不是本篇的内容,感兴趣的朋友可以看我之前文章(老架构)。这次改进了之前的诸多不合理的地方,顺便把 IP 和证书全部更换了一遍。

👉Dynamic k8s 集群实现方案

本文的目标读者

本文主要针对两类读者,一是 Cloudflare 的重度用户,在此前提下教你如何“针对性的优化和防护”;二是没用过或刚接触 Cloudflare 的读者,当然,在阅读本文之前,你最起码要使用过云服务器,也能够理解云服务中的相关概念。

如果对 Linux 和云服务不太熟悉,又或者是对 CDN、HTTPS、DNS 之类的网络技能稍有欠缺,建议你买一个便宜的云服务器简单学习一下,每个月 4 美刀的足矣。

概述

咱们既然是对 Cloudflare 和 WAF 扫盲,那么首先来介绍这俩吧。

Cloudflare 是一个全球网络,旨在让您连接到互联网的一切都安全、私密、快速和可靠。

这是官方介绍,说白了,它提供很多服务,但最出名的是 CDN 和 DDNS 服务。

WAF(Web Application Firewall,Web 应用程序防火墙)通过过滤和监控 Web 应用程序与 Internet 之间的 HTTP 流量来帮助保护 Web 应用程序。它通常保护 Web 应用程序免受跨站点伪造、跨站点脚本 (XSS)、文件包含和 SQL 注入等攻击。

注:本文的 WAF 主要指 Cloudflare WAF。

云服务攻击面

说到攻击面,这里我们就拿个人使用云服务来说(大规模云应用场景,我也接触的少,抱歉)。

  • 网络安全:攻击者拿到你的服务器 IP、不安全的传输协议(如 HTTP)等,再进行攻击操作。
  • 访问的合法性:如果每一个用户都能对你的服务畅通无阻的访问,那么必然会增大安全隐患。下面会讲到如何处理,毕竟我们需要保证正常用户的访问。
  • 网络攻击:DDoS 攻击,通常会导致云服务宕机。毕竟在个人笔记本上一通简单的操作,就能”瞬间“把学生机打进黑洞。下面我会聊聊,如何最大程度的“缓解” DDoS。

有心之人防不住,但个人云服务也可以设置一些规则来缓解。真正的大佬,没有必要浪费时间和成本来攻击咱,实际上大多数情况下防的是“无差别攻击”脚本。

当然,什么常说的软件安全、数据安全、供应链安全,不在本文的讨论范围之内,有兴趣的话,也可以找我聊聊!

加密通信

HTTPS 大家想必已经不陌生了,但是证书链“信任”问题,以及客户端到服务器的每一环,是否都进行了可信证书的加密,毕竟源站一旦暴露,各种烦人的脚本就来找你了。而且也要防止数据泄露,以及数据篡改。

这里贴一张官方的图,我们可以看到,图上有 2 把锁。其中浏览器和 Cloudflare 中间的锁,是边缘证书(Edge certificate),它是由Cloudflare 向访问您的网站或应用程序的客户出示的证书。而 Cloudflare 和源服务器中间的锁,是源服务器证书(Origin certificate),它会加密源服务器和 Cloudflare 之间的流量。

巧用阿里云 OSS 玩转免费分布式存储,原理就是这样,保证所有流量经过 CloudFlare 来实现“免流”。

同源策略

这里的同源策略,可能和开发中大家所理解的同源,稍微有点小区别,但原理差不多。

说白了就是结合 CDN 为静态资源设置同源策略,在提高缓存命中率的同时,降低“源站”被发现的风险。

为什么要重视云安全?

云安全(当然也可以扩展到数据安全等),我想我不用过多解释了,对于企业来说,关乎到“生死存亡”,可以说是不过分的。

那对于个人来说的话,我总结了如下几点:

  • 出于保护个人隐私的考虑。
  • 节约时间的考虑,配置好之后,把服务挂上去,可以显著减少维护时间,不至于天天浪费时间应付各种麻烦。
  • 从学习提升的角度考虑。在这个过程中,既能掌握理论知识,也能进行实战,何乐而不为呢😊

常见的攻击手段

简单解释下吧,我不可能教别人干这个,何况我的水平有限,也教不了。

基于 SOP 的攻击与跨域资源检测

SOP,也就是同源策略,是 Web 领域最重要的安全机制之一。一般来说,针对 SOP 的攻击,都是基于浏览器的,也就是“绕过 SOP 技术”。

我们知道,相同主机名、协议和端口,可以视为同一个来源。那么在“云服务”中基于 SOP 的攻击方式有哪些呢?

  • 直接针对资源进行攻击(通常静态资源都放在 CDN 了,这也是大家为什么经常看到“天价账单”)。
  • 对跨域资源进行检测,找出源站,进行攻击。

攻击的前提是,错误的配置了规则。比如资源允许跨域,导致其它来源可以疯狂请求资源。或者是缓存策略配置问题,导致缓存命中率不高。或者是只是对资源进行了缓存,但并没有把源站隐藏好。正确配置的话,可以极大的缓解攻击。

把 HTTPS 降级为 HTTP

这个也称为绕过 HTTPS,这里有个前提,即证书可不可信。

理论上来说,HTTPS 加密的内容,是不会在“传输过程”中泄露的,如果密钥泄露了那就好好反思下自己。

这里说一下很多人可能会忽略的一点,就是在服务端没有设置强制访问 HTTPS,甚至保留了 HTTP 访问,这是有很大的风险的。如果用户能直接通过 HTTP 访问到服务了,那么能拿到什么“有用”的信息,不用我多说了吧?

很多年前,我也犯这个错而不知情,也是后来才改掉的。我上了 HTTPS 通信后,就没有理由继续使用 HTTP 了。使用 HTTP,无疑是告诉别人,嘿,我的源站就在这儿,且无任何缓解防护,快来攻击我(doge

分布式拒绝服务攻击(DDoS)

分布式拒绝服务(DDoS)攻击是通过大规模互联网流量淹没目标服务器或其周边基础设施,以破坏目标服务器、服务或网络正常流量的恶意行为。

说白了,就是有很多“用户”,疯狂的把流量送到你这儿来,然后你扛不住了,就宕机了(同时也影响了服务的正常访问)。

当然,我们不可能把大量访问全当成攻击。所以需要对服务进行流量监控和分析。比如可以看看是不是只有某个 API 或者页面的流量激增、访问者的 IP 地址或者 IP 范围是不是很可疑之类的。或者说用户的设备类型、地理位置、浏览器标头等等,是不是大量重复了。

“发现”服务器 IP 地址以及域名枚举

这个很多人可能不太明白啥意思,我们首先来看一张图。

这里使用了 censys.io 的服务,只要输入一个域名,它就能查询所有该域名(包括子域名)下的源站信息。它会进行批量扫描,且进行证书关联(证书里面有域名),也同时会扫描你所有的端口。当然,也有其它方式,如果你实在是想防住它,可以直接在防火墙关闭它的扫描子网 IP 对你服务器的访问。

虽说关了用这个网站就查不出来的,但这种方式仍然没有杜绝,其它平台/个人依然可以这个扫出来。

图中扫描出了一台我的服务器信息(我只留了这一个用作演示,因为这台服务器宕机没啥影响)。有朋友可能就要问了,这里我已经基于 Cloudflare 配置好了,为什么还是泄露了源站呢?

按平台的分析也是属于证书泄露,基于我对其它的服务器的设置进行对比,我确定是“监控塔”把我的证书泄露了,但到底是我配置错了,还是其它什么原因,我就不管了(退一万步来说,是我配错了,我不用你了还不行吗?)。然后和 Aria2 的 HTTP 端口匹配到了相同的 Body Hash,并且指向了一个 Ngixn 的漏洞,真是防不胜防啊!

挑战黑洞攻击(CC)

挑战黑洞攻击(CC)是一种网络攻击,类似于DDoS攻击,但它针对的是目标网站的特定URL或页面。攻击者利用大量的计算机或设备向目标URL或页面发送请求,使其过载并无法正常工作,从而导致服务中断或不可用。

这个攻击有什么用呢?就比如用 Cloudflare 代理 OSS 的流量,虽然不需要出流量费用了,但是请求次数是需要计费的,也就是防 D 不防 C。

IP 欺骗以及其它

IP 欺骗是指创建源地址经过修改的 Internet 协议 (IP) 数据包,目的要么是隐藏发送方的身份,要么是冒充其他计算机系统,或者两者兼具。恶意用户往往采用这项技术对目标设备或周边基础设施发动 DDoS 攻击。

应对措施

终于到实战环节了,下面咱们就来看看,怎么使用 Cloudflare 的各种配置,来缓解各种攻击以及保护云服务吧。

DDoS 缓解

首先让我们来了解一下,在应对 DDoS 攻击时,要先做什么?答案是:检测。没错,我们必须要先判断,到底是“攻击”,还是说确实是网站“太受欢迎”了🤣,我们要能够区分攻击流量与大规模正常流量。

在提供了 DDoS 缓解的服务商平台,一般有 2 种方式来进行。其一是平台自己的自动缓解措施,也就是全托管形式,又平台自动判断是否遭受了攻击,并进行防护。其二是自定义 DDoS 托管规则,比如 CloudFlare 就是可以自定义规则用于匹配第 7 层(应用层)的攻击媒介。

按图中所示,首先我们找到 部署 DDoS 替代

然后进行填写和选择,并保存。“规则集操作”和“规则集敏感度”就按照自己的需求来了。

需要注意的是,支持自定义的是 HTTP DDoS 攻击防护,而网络层和 SSL/TLS DDoS 攻击防护则是自动缓解的。

你说你不知道自己的需求?那你就跟我一样,使用平台自定义的就行了。

Web 应用程序防火墙(WAF)及 API 保护

WAF 用来缓解恶意请求的流量,根据图中的位置,安全性 -> WAF -> 创建规则

然后开始配置,比如我这里需要对完整的 URI 进行判断,把 api.besscroft.com 下的所有请求全部采取跳过匹配,并记录下来。因为我的 API 是配置了反向代理的,如果直接启用“质询”的话,会出现 403 错误,也就是说没法在页面上加载这个“质询会话”,就是下图所示的内容:

而我们刚才勾选的记录,则会在事件栏中被记录下来。

我是直接全站启用了,因为这样省事儿,你可以理解为这样干的话,自定义配置就变成白名单模式了。而如果你不知道你需要哪些规则的话,你也可以先全站启用,然后自己访问网站看看,再根据事件中的请求详细信息,针对性的调试配置即可!全站启用在 概述 -> Under Attack 模式,直接打开即可!

WAF 的速率限制规则咱们下面会说,至于托管规则,免费用户就不需要管了,如果你想获得更全面的保护、全套的 Cloudflare 托管规则以及防火墙分析,你应该付费啦!

WAF 工具配置,可以自定义规则,声明哪些条件下的用户可以访问。比如 IP 访问规则,ChatGPT 应该就用了这个配置,拦截了某些地方的 IP 访问,很多用过的小伙伴,应该能看到“5 秒盾”(破盾方法当然是有滴)。而在某些地方,访问 ChatGPT 甚至可以说是双向墙了,我不说是哪里🤡。

不过工具配置我都没有添加,因为我暂时还没有类似的需求,也不需要阻止爬虫之类的。

加密证书管理(交给 Cloudflare,降低风险(争议性))

这个标题,为什么我加上了争议性呢?因为你如果认为 Cloudflare 是不可信的,那么确实风险是挺大的,尤其对于企业来说。但是对于咱们个人用户来说,还是能用用的,Cloudflare 没有必要狠狠的砸自己的招牌(大概?

首先我们找到 SSL/TLS -> 概述,然后把加密模式在 完全完全(严格)直接二选一。如果你信不过平台的证书,你用自己的证书也是可以的,看自己需求了。然后 SSL/TLS 建议程序的话,我推荐你打开,有时候确实会收到提示邮件(万一自己有漏配置呢,对吧?

然后图中的 配置规则,和刚才的一个意思,我同样配置了 api 子域名跳过。

DNSSEC

DNSSEC 可抵御伪造的 DNS 应答,也就是保护你的 DNS 解析不被恶意篡改的。

当我们把域名的解析交给 Cloudflare 管理后,在 DNS -> 设置 里面,启用设置,并按照要求,在域名服务商哪里,配置好 DS 记录 即可!

服务器防火墙管理(仅允许来自 Cloudflare 的流量)

这里看标题就知道要干啥了,我建议最好配置上。首先我们访问 Cloudflare IP Ranges,然后将所有 IP 段下的地址,添加进防火墙。

这项措施主要用于进行 API 防护,我上面说,我的 API 要进行反向代理,那么我必须加上这个配置。当然,这里我是直接偷懒了,我用了 CloudPanel 作为服务器管理面板,它有个功能,叫做 仅允许来自 Cloudflare 的流量,直接启用即可!

使用 Rate Limiting 来防止暴力破解和第 7 层 DDoS 攻击

我们有时候,可能需要防止暴力破解,或者说就想防止攻击。但是有的请求,看上去就是伪装的非常正常,根本分辨不出来。这个时候我们就可以限制请求速率了,你一个正常访问的普通用户,总不至于点的飞快吧...

如图,我们可以限制匹配到任意 URI 的请求,同 IP 在多少秒内只能请求多少次。我这里配置了 10 秒钟 50 次,更严格实际上也没问题。

前面说到的 Under Attack 模式,也可以在 安全性 -> 设置 里面启用。而质询通过期,则是在设置的直接过后,要再来一次,否则就无法继续访问请求。去年下半年(2022 年)我使用 ChatGPT 时,就能察觉到开启了这个功能,因为打开了 Chat 页面一段时间后,在当前页面提问后,ChatGPT 就无法给出答案,而是说网络错误相关的提示。当时也很好解决,打开一个新的浏览器标签,过掉验证,然后再关上,就能在当前页面继续使用 Chat。而现在,ChatGPT 明显新增了不少规则,有付费的,也有其它的,有部分我能试出来,但有些还是第一次见。

Q&A

HTTP 和 HTTPS 有什么区别?

HTTP 传输的数据是明文的,不安全;而 HTTPS 使用加密技术保护数据传输,更安全。HTTP 适用于传输非敏感信息,HTTPS 适用于传输敏感信息。

浏览器在使用 HTTPS 通信时,代理(如 Cloudflare)可以看到通信内容吗?

一般来说的话,是没法看到的。这种端到端加密,只有客户端和服务端可以看到数据的内容。但是呢,请求元数据是可以看得到的,也就是咱们经常说的,看不到你访问网站的内容,但是知道你访问了什么网站。

但是呢,Cloudflare 充当了中间人(Man-in-the-middle, MITM),而且一般会使用它颁发的证书,所以...懂我意思吧?

反向代理和源站是什么?

源站,可以理解为“来源”站点,也就是咱们藏在 CDN 后面的原始服务器。用户请求时,CDN 会先看看自己有没有缓存资源,有的话直接响应给用户,如果没有的话,会向源站请求,并按照缓存规则,看是否要缓存下来,以及怎样缓存,并把资源响应给用户。

反向代理是位于一个或多个Web 服务器前面的服务器,拦截来自客户端的请求。它会接受用户的请求,转发给源站,并“代表”源站,向用户发送响应。

为什么使用了 WAF 后,日志中没有真实的访问者 IP 了?

因为流量被 Cloudflare 接管了,你看到的都是 Cloudflare IP。我们可以在 HTTP 请求标头 中查看到客户端 IP 地址,或者直接在源站日志中恢复原始访问者 IP

最后

本文其实只讲到了一小部分,也是我在使用过程中积累的一点点经验,希望能帮到各位读者朋友。Cloudflare 平台上还有各种各样的设置和功能,它能做的事儿远不止这些,它特别的强大。我每年的云服务费用就只有域名的费用,原本每年几十块,今年又买了个新的,现在手里一个 com 和一个 dev 后缀域名,每年就只消费一百多而已。可以说我的整个接入层,和部分基础设施,全部基于 Cloudflare 在管理,真的非常好用且方便。

文章写到这里,也欢迎各位朋友与我交流!

对爱情的渴望,对知识的追求,对人类苦难不可遏制的同情心,这三种纯洁而无比强烈的激情支配着我的一生。

Three passions,simple but overwhelmingly strong,have governed my life:the longing for love,the search for knowledge,and unbearable pity for the suffering of mankind.

—— 《我为什么而活着》罗素 (哲学家 数学家 思想家)

时间与人生——网络、生活

好像挺久没有写下文字了,不知道是因为大脑想休息,还是单纯的懒。

赛博社交

这个月解散了一个 6 年的 QQ 群,虽然基本上算是个死群了,但是有时候屁事儿也多,实在是没精力去维护,干脆解散了。群里面大多数的人,实际上我根本就不认识,实际上这个群的成立本身就没有很强的目的性。我记得最开始好像是我的读者群来着🤔可能以后会建一个新群吧,只让兴趣相投的人进来,这相当于是设立了一个门槛了。

注销、停用了几乎所有的国外社交账号,比如推特。当然,其中有一些不太方便说的原因。除此之外,浪费大量的时间,去处理诸多网友与你的互动,并不一定具备积极意义。同时还得忍受各种骚扰,辱骂,现在的互联网也确实是这个面貌。当然,我也认识了不少朋友,大家也能通过各种其他方式同我交流~

网络

这段时间整理了自己大部分的网络资源,让冲浪变得更有意义。前面说到,有些账号只是停用,是因为我觉得他还有用得到的地方。很多平台实际上是可以当作搜索引擎的结果来源的,你也许能搜到自己想要的信息或者资料,只不过在“过滤”处理时,容易陷进去,一直刷,停不下来。

抽空整理了一下书签栏,主要把我平常去过和知道的站点,我认为重要的,全部都整理下来了。拿文档来说,细分了不同语言、方向的文档,便于我在需要的时候,直接点开,省去了使用搜索引擎的时间。

订阅列表这边,按照不同的维度进行了区分,跟我的博客一样,没有明显的标识性的,我一律放在了博客区间。

  • 大佬—这个是看过了许多站点之后,我筛选出来的,我认为每一篇文章,都会对我的思维能力,认知、学习能力有影响的博客。有几位厉害的,我相信玩 GitHub 的人应该都知道。
  • 订阅—一般是周报、月报、期刊或者是技术团队之类的,比如大伙儿每周五都会看的阮一峰周报,或者是 Netflix TechBlog。
  • 博客—顾名思义,但也有些筛选条件。比如有的域名已经停止解析挺久了,这种情况下我会去搜一下域名到期没,或者该作者是不是有了新站点,有些作者会在换域名后,将旧域名重定向。或者说长达一年以上未更新,且评论区被注入了大量广告的,我基本上都会移除。
  • 作品集—就是大量内容的集合,可以是原创、翻译、整理等等。举例 2 个不同的,金步国作品集中文诗歌
  • 国外博客—这里主要存放的是国外友人的博客,比如我毕竟欣赏的Richard Mattka,比如站点名称很有个性的0X74696D
  • 艺术—这里我把艺术类和文学类站点放在一起了,比如卡尔维诺中文站

当然,这些订阅列表,大部分都有 RSS,会被我用 Feedly 订阅,因为数量实在是有点多,我不可能每天挨个打开看看有没有更新,除非我实在是闲得慌。

生活

调整了一下生活状态,周末不再宅在房间了,以前除了工作日,每个周末都会打游戏、学习和写代码,甚至学习的时间远大于打游戏的时间。从我毕业以来,两年多吧,几乎都是如此。我最近在思考,意义何在,我收获了什么,又失去了什么?

今年的求职市场,真的是应了去年的一句话:“2022 年,是未来十年最好的一年。”

失落感其实是有的,但学习和编程已经被我培养成了兴趣,就连我以前害怕学的英语,也在多邻国坚持学习了 242 天了。于是我做出了我的行动,把我的数字生活给优化了,在保证其它时间没被压缩太多的情况下,周末还能够出去走走玩玩。今年打算攒钱搞个微单,记录一下旅途的风景。武汉的春天,还是有很多景点可以去去的~

网络是网络,生活是生活。

巧用阿里云 OSS 玩转免费分布式存储

前言

说到对象存储,应该很多人都用过吧。先不说国外云厂商提供的服务,就拿国内的来说,大伙儿应该都用过阿里云 OSS。很多小伙伴选择用它来做图床、博客、甚至是拿来做冷备份(毕竟比百度网盘还是靠谱点的),不过对象存储昂贵的存储费用、流量费用、以及请求次数费用,都让不少个人用户相当头疼。这篇博客是想提供一种新思路,采用 CloudFlare CDN 来进行 OSS 资源的数据传输,以达到免流的目的。

如何实现

介绍

先来介绍一下吧,带宽联盟是 Cloudflare 推出的一项服务,由一群具有前瞻性思维的云服务和网络公司组成,致力于为共同客户降低或免除数据传输(带宽)费用。为什么能做到非常低甚至能免除成本呢?云厂商跟 Cloudflare 直接的数据传输,是通过专用网络接口 (PNI) 或专用互连的,中间不经过任何网络提供商(比如电信),既然是直连,那么就不存在 PNI 的增量成本了,自然也就便宜了。虽然阿里云不是第一批加入带宽联盟的,但是到现在为止也加入一年多了(我白嫖也一年多了🤣),并推出了 Cloudflare+Alibaba Cloud OSS 的解决方案。这点还是非常良心的,虽然腾讯云后来也加入了,但是我觉得不够“清晰透明”,就一直没试过。

虽然有时候 Cloudflare 是“减速 CDN”,但是既然咱选择了白嫖,那么就要贯彻到底了🐶,对于有海外业务的小伙伴来说,这样反而能省下不少的开销呢。不像某些厂商,带宽成本极低,反而收取高昂的费用(说的就是你,AWS)。

网上存在一些争议,说只能阿里云国际这么玩,国区不行。。。这里贴上国区说明文档。而且,经我自己测试,国区也用了一年多了,确实也没花钱。

费用问题

上图为我国区账号的使用数据。我这里先讲清楚费用相关的问题,解决大家可能有的疑惑,以免误操作导致花钱!

  • 存储费用

根据存储费用文档,我们可以了解到,在海外(部分)区域,标准存储(本地冗余)容量支持使用5 GB/月的免费额度(即每月标准存储(本地冗余)容量≤5 GB时,不收取标准存储(本地冗余)容量费用)。

虽然不支持中国大陆免费 5GB 存储,不过并没有关系,支持的话我也不推荐你用,往下看就明白了。

  • 流量费用

根据流量费用文档,我们可以了解到,在海外(部分)区域,外网流出流量(oss_flow_out)支持使用5 GB/月的免费额度(即每月外网流出流量≤5 GB时,不收取外网流出流量费用)。

有的小伙伴可能会好奇,既然可以免流,那这 5GB 外网流出流量还有什么用呢?看我上面那张图,你会发现,外网流出流量,无法做到完全没有。我每个月都有几 KB 的漏网之鱼,这还是我用量少的情况下,用的多自然就可能漏的多。原因就是你无法把缓存命中率做到 100%,可能我设置方式不是最优,但是能做到接近 100% 也就够了。但我们还需要防范直接打到源站的流量,这 5GB 相当于一个缓冲,如何防范打到源站,我下面也会讲。

  • 请求费用

根据请求费用文档,算了没必要看了,请求费用是需要收费滴,不过好在便宜,几乎可以忽略不计。

想必有经验的小伙伴已经察觉到了,这套方案防 D 不防 C,不过方案是有平替的,只是各有优劣。但对于本身有这个需求的用户来说,确实能省钱。

  • 最后,是 Cloudflare 这边的费用

对于阿里云来说,传输到 Cloudflare 是零出口费用

有一点需要特别注意:出口传输费优惠或豁免可能需要与托管服务提供商注册,不适用于源于中国大陆的数据传输。也就是说,OSS 源站必须是海外节点,所以大陆节点没有免费 5GB 存储,其实无所谓的啦!

那么我该如何免流呢?

别急,咱一步步来!首先,准备一个阿里云账号,这里不管是中国区账号还是阿里云国际账号都是支持的哦!为了方便大家,我就用我的国区账号来演示吧,不过国区账号用的少,我主要还是用阿里云国际来操作的。

创建 Bucket,注意 Bucket 名称一定要取好,然后地域选择海外的,比如我这里选择的是中国香港区域。存储类型选择标准存储,读写权限选择公共读,其它的默认就行了,然后我们点击确定进行下一步。

这时候我们来到存储桶控制台,可以看到外网访问的域名,我们复制这个域名,然后到 Cloudflare 去配置解析。

这里的解析类型选择 CNAME 解析,然后填入我们刚才复制的域名,开启代理即可!

然后我们回到 OSS 控制台,找到传输管理——域名管理,绑定域名,把我们刚才配置解析的域名添加进来。

然后我们查看域名绑定配置,发现已经绑定上了。然后我们去上传一张照片。

自有域名选择自己配置好的解析域名,我们就可以看到 URL 已经变成咱们自定义的啦!

批量管理其实也就是域名用自定义的。

然后访问这个地址,发现可以正常访问了!

一些必要配置

能访问到图片了,说明已经可以正常使用了。但是,还有一些配置,我建议你加上。

防盗链、跨域设置的话,可以根据自己的需求来,这个是不强制的。

关于授权策略,这个一定要加,访问 Cloudflare IP Ranges 页面,将所有的 IP 都添加进来,最大程度的保证访问安全。

这里的静态页面,我建议你一定要配置上,不然请求到空资源时,请求方能看到你的源站信息,然后就能通过技术手段绕过 CDN 直接请求源站,这也是这套方案最大的风险。所以为什么我上面说我喜欢用阿里云国际账号玩这个呢,因为那是我的小号,不担心“天价账单”。

然后我们再去 Cloudflare 添加页面规则,提高缓存命中率。

最后

采用阿里云 OSS 这种商业方案,风险是有的。但是对于适合的用户来说,反而能省钱。而且,经我自己测试,我开了很多存储桶,一个存储桶 5GB 空间,那么我将这些存储桶管理起来,就可以当初分布式存储玩了(当然哈,并不是真正的分布式存储,区别大着呢🐶)。不过一般降低风险的平替,我们都采用 Backblaze ,这家的存储还是免费 10GB 呢,做个博客图床绰绰有余了。

时间与人生——面试随想

她那时候还太年轻,不知道所有命运赠予的礼物,早已在暗中标好了价格。——《断头王后》茨威格

来谈谈这次裸辞对我带来的影响,以及我自己的一些总结反思。

抉择

离职的原因,嗯。。。不想再多提了,毕竟已经是过去的事情了。与其想原因,倒不如想想,这次裸辞找工作,给我带来了什么。至于为什么换城市,在杭州面了3个多星期,只拿到了一份 12k 的 offer,信心被击垮了,就想着回武汉找找吧。虽然说要尊重自己的决定,既然确定了,就必须面对,对自己负责任。当然,那种精神状态下,我可能是难以保持冷静和理智的,容易被情绪影响。

面试

对于面试,其实离职前,我并没有报太大的希望。我的学历属于比较差的那一类,在简历上我都是放在最后的。最开始在简历上写了很多东西,满满四张纸,后来有个面试官提醒我说:“你的简历上的东西太多了,我知道你都会,但是别人随便哪一个深挖就能把你问死”。后来我就将简历精简到 3 张纸了,第一页就是基本信息、专业技能、工作经历、工作描述。这样做的原因,是考虑到每个 HR 对技术的了解程度不同,甚至是不了解,她们可能就是根据用人部门给出的 JD(Job Description),来对比简历上的技术名词判断匹配度的。

在投简历时,我的简历一般是 2 种,一个通用简历,专门用来海投。一个是在详细了解岗位后,针对性修改过的简历,比如说对于 JD 上的要求,我会调整项目和专业技能的顺序和说辞,提高岗位匹配度。

如果有小伙伴想参考我的简历,我可以发你一份脱敏的简历。

面试准备

对于面试准备,我其实是准备不足的。平常上班没时间去刷题,周末学习也是在看书和折腾自己的项目,根本不会想着说去刷面试题。虽然我很反感背题,因为我觉得学编程背题就违背了我的初衷了。话说回来,我确实也没学好,不然怎么会答不上呢(这里已经暴露出我学习方法有些问题了,学是学了,面试一紧张就答不好)。显示是很骨感的,面试了几家之后,我终于开始背面试题了。。。

到底是谁的问题?

今年就业环境真的比以前差不少,在 21 年年初的时候,找工作还是非常好找的,面试机会多,offer 也多。但是面对面试官的进攻,我如果能防守的无懈可击,那大概率是能拿到 offer 的,问题就出在我没有做到。面试虽然是双向选择,但是面试官考察你的工作能力和技术能力时,自己必须表现得好才行。

我拿自身经历来说吧,对比在杭州和武汉的面试,杭州的面试官就正常的多,武汉这边的面试官傻逼居多(真的就是纯傻逼!),面试体验也是杭州明显要高一个档次。大家也都知道,面试的时候作为求职者,我们是必须去引导面试的,让面试官问出你想让他问的一类问题。在我认为正常的面试中,问题主要是出在我这里的,心态不好和菜。

好的面试为什么这么重要?

我来聊聊我认为的好的面试是什么,面试也是在寻找志同道合的小伙伴,或者说优秀的开发人员。我并不是给自己硬性条件不好找借口,但我还是想说说,那些不好的“招聘条件”:

  • 全日制统招本科学信网可查。(这个其实我可以理解,很多甲方要求资质,只要你不因为学历而鄙视人就行。我们评价一个人,应该是他的品行,而不是他的出身和学历)
  • 必须是对应专业的。(这点卡死实际上说不通,转行比科班优秀的也是有的)
  • 年龄和性别限制。
  • 工作年限限制。(可以有限制,但很多 HR 在回复的时候,把工作年限和能力划等号属实不应该!)

这里我要给一个投简历时的小技巧,一定要让 HR 把简历转发给用人部门看,不然不要去面试。技术面试如果不是用人部门主导,那么这种公司不见得会有多好的。一个有良好管理的公司,怎么可能把这么重要的事情交给对技术不懂的 HR 来决定呢?面对这种情况时要慎重!!!同时要保证是团队自己的 Leader 招人,如果是帮忙招人,或者招完就离职的,谨慎考虑。

实际上很多中小公司在招聘的时候,考察的侧重点就很离谱。比如武汉这边很多公司就只考八股文(不是说问的怎么样,就纯背题了),然后看你能不能加班、能不能出差、工资低不低。。。而比较好的面试官会考察你的性格(考察应聘者是否正直,以及能否很好的控制自己的情绪)、对编程的兴趣(是喜欢编程,还是仅仅为了赚钱)、学习能力以及协同开发能力(可以直接问如何跟不同的同事配合工作)。

收获

从 6 月到 7 月,断断续续面试,经历的挫折也是不少。在一次次面试中,我也明白了自己的不足,正视他,才能做出改变。万幸的是,在我经济还能支撑的时候,社会给我上了一课。这一个多月中,也曾想过转行的问题,毕业 2 年攒的钱,还没有我爸 6 月份收入多。尤其是我过去一年,对学习投入的时间是远大于打游戏的时间的,心理落差也是有的。

不出去看看,确实不知道自己有多菜,因为平常一直在自学,面试实际上就是最好的考核之一。每次去面试的路上,除了公交地铁基本都是步行。读万卷书,行万里路,在路上我见过为了生活奔走的人、在地铁站躺地上睡觉的人、在公共厕所洗漱的人,也碰到了不少农民工,跟他们聊天得知根本不了解、融入不了这座城,只是出来挣钱。我又何尝不是一样呢,只是个再普通不过的人罢了,这是我踏入社会后第一次认真观察这个世界。

学习计划

我的数据结构和算法、JVM以及数据库深入的知识,都是比较菜的地方,也是我后面需要重点学的一些方向。详细的计划我就不公开了,毕竟计划做的再好,也得自己去坚持完成才行。原本是 markdown 文件加上思维导图的方式,去记笔记和总结的,这段时间用了下 Jira,发现很多重复的任务直接自动化更省事儿。

未来

回武汉我不知道我能工作多久,目前是走一步看一步了,今年肯定不会再出去了。而且想出去手里面钱也不够,我不想找父母要钱,不想依赖他们。今年家里的房贷和负债可以全部还完,算是一件好事。明年等疫情稍微好点儿,可能会去北京或者上海吧,毕竟还年轻,多出去看看,家里也是支持的。

学习当然也不能落下,编程一直在坚持学,专升本也在弄了。我每天都坚持在多邻国上面学英语,希望考试能过~

最后,我相信一切都会好起来的~我觉得我可以尝试去找个女朋友了🙃

我的 Java 测试最佳实践

介绍

什么是测试?

软件测试(英语:software testing),描述一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。依照可计算理论(计算机科学的一个支派)一个简单的数学证明推断出下列结果:不可能完全解决所谓“死机”,指任意计算机程序是否会进入死循环,或者罢工并产生输出问题。换句话说,软件测试是一种实际输出与预期输出间的审核或者比较过程。—— 软件测试 Wiki

为什么要做测试?

软件测试的经典定义是:在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。

  • 从业务角度出发,定义好功能测试的预期结果,在不运行代码的前提下,通过测试反馈输出结果,来验证业务和功能的可行性。
  • 从项目角度出发,可以清晰的了解程序内部的运行过程、细节和边界条件,一定程度上保证代码重构的安全性,让接盘的你和接你盘的同事,能放心的动代码。。。🥲
  • 从质量角度出发,可以复现任何上游或下游出现异常时的情况,以及被引用代码造成的业务影响,从而构建出高可用性的代码,保证核心业务的稳定性。

开发模式

开发模式,主要是 2 种,我目前公司的开发方式,更接近于 BDD 开发,而我阅读的《Java 测试驱动开发》,则讲述的是 TDD。

BDD:即行为驱动开发。BDD 要求系统最终的实现与用户(产品)的行为是一致的,验证代码实现是否符合原型设计目标。它侧重与整个系统的行为,关注的核心是设计,是测试驱动开发的延伸。

TDD:即测试驱动开发。TDD 的流程要求你先编写测试,再编写实现代码。它侧重于单个方法或特性。

测试驱动开发中,先编写的测试代码,也算是单元测试的一部分。

测试类型

  • 单元测试:旨在对小型功能单元进行检查。在 Java 代码中,这些单元就是【方法】。
  • 集成测试:旨在核实各个单元、模块、应用程序乃至系统被妥善地集成在一起。在 Java 中,我们一般按照设计要求,会把多个单元测试组装起来,进行集成测试。
  • 功能测试:功能测试就是对产品的各功能进行验证,根据功能测试用例,逐项测试,检查产品是否达到原型和需求文档要求的功能。
  • 验收测试:它和功能而此时的用途不同,但是目标相似。在我们公司,它的实践是黑盒测试,主要交由测试人员完成。无需了解代码和程序内部的情况,测试案例依照原型和需求文档的要求而设计。

测试框架技术选型

常用的测试框架:

  • Junit 是一个 Java 语言的单元测试框架。
  • Mockito 是一个在 MIT 许可下发布的 Java 开源测试框架。该框架允许在自动化单元测试中创建测试双重对象(模拟对象),以用于测试驱动开发或行为驱动开发。
  • EasyMock 通过使用 Java 代理机制动态生成模拟对象。
  • PowerMock 使用自定义类加载器和字节码操作来模拟静态方法、构造函数、最终类和方法、私有方法、删除静态初始化程序等。
  • JMock 是一个支持使用模拟对象对 Java 代码进行测试驱动开发的库。

在日常开发中,我基本上见过最多的单元测试,基本上都是用 Junit 完成的。也有许多团队是采用的 JUnit + Mockito 组合使用。其它的测试框架比较少见,可能是因为国内用的少了,也可能是我见识少了~。不过话说回来,国内真的有很多公司不注重这一块,虽然单元测试是把双刃剑,但是它带来的好处也是很不错的。

最佳实践

最佳实践,主要围绕 SpringBoot 工程的项目来讲解,如果你要在其它框架诸如 Vert.x 中使用,请自行查询引用方法

快速上手

  • 导入测试所需的依赖包
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>

这里有一点我们需要注意的是,在 spring-boot-starter-test 包中,已经集成了 Mockito ,所以不需要单独引用,开箱即用即可。

  • Mapper 层代码
1
2
3
4
5
6
/**
 * 根据用户名查询用户信息
 * @param username 用户名
 * @return 用户信息
 */
User findByUsername(@Param("username") String username);

注意,这里的 Mapper 层指代 持久化层 ,在其它项目中,也可能叫 Repository 层。

  • Service 层代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Slf4j
@Service
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
/**
 * Mockito 使用注解注入依赖关系,需要提供构造器
 */
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public AjaxResult login(String account, String password) {
User user = userMapper.findByUsername(account);
if (null == user) {
throw new BusinessException("暂无该用户!");
}
if (!Objects.equals(user.getPassword, password)) {
throw new BusinessException("密码错误!");
}
return AjaxResult.success("登录成功!");
}
}

注意,这里只是模拟,实际开发中步骤不会这么少的。

  • 测试代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Slf4j
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
@DisplayName("登录测试")
void login() {
// 准备测试数据
 String account = "admin";
String password = "666666";
AjaxResult login = userService.login(account, password);
// 验证是否与我们预期的状态值相符
 assertEquals(HttpStatus.SUCCESS, login.get("code"));
assertNotNull(login.get("data"));
log.info("登录方法测试成功.[login={}]", login);
}
}

运行单元测试,看到 登录方法测试成功 ,即表明成功!

数据库访问测试

数据库访问测试,应该是单元测试中,大家关注最少的地方了,有种脱裤子放屁的感觉,但实际上它也是有适用场景的。举个简单的例子吧,咱们在用 mybatis 开发复杂的业务场景的查询时,经常需要【变动】,也就是调整 SQL 语句。这时往往去启动项目调试,会非常麻烦且浪费时间,可能有时候你多打了一个 , ,也不一定能及时发现。那么在以往的开发中,累计下来的测试案例,可帮助你迅速的测试数据库访问的单元测试,及时发现问题。

  • Mapper 层代码(此处省略 xml 文件)
1
2
3
4
5
6
7
8
public interface UserMapper {
/**
 * 根据用户名查询用户信息
 * @param username 用户名
 * @return 用户信息
 */
User findByUsername(@Param("username") String username);
}
  • 测试代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Slf4j
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
@DisplayName("根据用户名查询用户信息测试")
void login() {
// 准备测试数据
 String username = "admin";
User user = userMapper.findByUsername(username);
// 验证是否与我们预期的状态值相符
 assertEquals(username, user.getUsername());
assertNotNull(user, "获取用户信息失败!");
log.info("根据用户名查询用户信息测试成功.[user={}]", user);
}
}

运行单元测试,看到 根据用户名查询用户信息测试成功 ,即表明成功!

业务测试

在业务层,通常会有许多的依赖关系,我们在测试时,需要隔离依赖,同时也得遵守 BCDE 原则

  • Border:边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等;
  • Correct:正确的输入,并得到预期的结果;
  • Design:与设计文档相结合,来编写单元测试;
  • Error:强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得到预期的结果;

这里还是以刚才的登录场景为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Slf4j
@Service
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
/**
 * Mockito 使用注解注入依赖关系,需要提供构造器
 */
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public AjaxResult login(User User) {
User userResult = userMapper.findByUsername(loginParam.getUsername());
if (null == user) {
throw new BusinessException("暂无该用户!");
}
if (!Objects.equals(user.getPassword, password)) {
throw new BusinessException("密码错误!");
}
return AjaxResult.success("登录成功!");
}
}
  • 测试代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Slf4j
@SpringBootTest
public class UserServiceTest {
@Mock
private UserMapper mockUserMapper; // 通过注解模拟依赖的接口或类

@InjectMocks
private UserServiceImpl userService; // 通过注解自动注入依赖关系
 private static username = "admin";
private static password = "666666";
private static User user;
@BeforeAll
static void beforInsertTest() {
user = new User();
user.setUsername(username);
user.setPassword(password);
mockUserResult = new User();
mockUserResult.setUsername(username);
mockUserResult.setPassword("666666");
}
@Test
@DisplayName("登录测试")
void login() {
// 验证测试用例是否创建
 assertNotNull(user, "user is null");
// 模拟登录业务中,依赖的 mapper 层查询接口
 UserMapper mockUserMapper = mock(UserMapper.class);
// 将模拟的接口注入
 UserServiceImpl userService = new UserServiceImpl(mockUserMapper);
// 当程序运行时,模拟查询结果,返回我们指定的预期结果
 when(mockUserMapper.findByUsername(username)).thenReturn(mockUserResult);
AjaxResult loginResult = userService.login(user);
// 验证是否执行
 verify(mockUserMapper).findByUsername(username);
// 验证是否与我们预期的状态值相符
 assertEquals(HttpStatus.SUCCESS, loginResult.getCode());
assertNotNull(loginCallResult.getData());
log.info("登录方法测试成功.[loginResult={}]", loginResult);
}
}

运行单元测试,看到 登录方法测试成功 ,即表明成功!

HTTP 接口测试

接口测试,在业务测试的基础上,还得加上 AIR 原则。AIR 原则和 BCDE 原则在阿里巴巴 Java 开发手册上都有,可以自行查看。

  • Controller 层代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class UserController {
private final UserService userService;
/**
 * 登录接口
 * @param loginParam 登录参数
 * @return token 信息
 */
@PostMapping("/login")
public AjaxResult login(@RequestBody @Valid LoginParam loginParam) {
log.info("登录请求:{}", loginParam);
AjaxResult accessToken = userService.login(loginParam.getUsername(), loginParam.getPassword());
log.info("登录请求成功:{}", accessToken);
return accessToken;
}
}
  • 测试代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Slf4j
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
private static LoginParam loginParam;
@BeforeAll
static void beforeUserControllerTest() {
loginParam = new LoginParam();
loginParam.setUsername("admin");
loginParam.setPassword("666666");
}
@Test
@DisplayName("登录接口测试")
void login() throws Exception {
// 验证测试用例是否创建
 assertNotNull(loginParam, "loginParam is null");
// 发起测试请求
 MockHttpServletResponse response = mockMvc.perform(MockMvcRequestBuilders.post("/user/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginParam)))
.andDo(MockMvcResultHandlers.print())
.andReturn()
.getResponse();
// 验证 http 状态码
 assertEquals(HttpStatus.SUCCESS, response.getStatus());
Map map = objectMapper.readValue(response.getContentAsString(), Map.class);
// 验证业务状态码
 assertEquals(HttpStatus.SUCCESS, map.get("code"));
log.info("登录接口测试成功:{}", map.get("data"));
}
}
  • 测试结果
MockHttpServletRequest:
HTTP Method = POST
Request URI = /user/login
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"40"]
Body = {"username":"admin","password":"666666"}
Session Attrs = {}
Handler:
Type = com.besscroft.pisces.admin.controller.UserController
Method = com.besscroft.pisces.admin.controller.UserController#login(LoginParam)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/json"]
Content type = application/json
Body = {"code":200,"data":{"token":"token","refreshToken":"refreshToken","tokenHead":"Bearer ","expiresIn":86399},"message":"登录成功!"}
Forwarded URL = null
Redirected URL = null
Cookies = []
登录接口测试成功:{"token":"token","refreshToken":"refreshToken","tokenHead":"Bearer ","expiresIn":86399}

高级技巧

代码覆盖率

好的单元测试能够最大限度地规避线上故障,这也是我们写单元测试的原因,在某些情况下,我们需要了解代码覆盖率。

代码覆盖率,也称为测试覆盖率,可衡量自动化测试执行的代码比例。

代码覆盖率工具针对特定的编程语言。 其使用一系列标准衡量覆盖率,包括代码行数、方法或函数、分支和条件。 您可以使用代码覆盖率工具识别代码库尚未被自动化测试覆盖的部分。

一般我们会用 Idea 自带的覆盖率工具,或者 JaCoCo 进行测试。当然,在代码提交时,也会在 CI 管道中进行自动化测试!下面是 Idea 覆盖率工具的截图:

CI 自动化测试

CI/CD 流程可实现短迭代周期的敏捷方法,提供快速反馈,并允许少量多次地发布更新。 测试是这些短迭代周期的关键部分,用于自动验证新代码是否有效和具有破坏性。

在开发中,自动化测试会节省很多重复的操作,节约大量的时间,但是这也对测试人员的要求更高了。测试人员需要定义测试用例,有时候还需要和开发合作编写自动化测试,而且有些东西,是无法自动化测试的,也需要测试人员操作。

测试一般在 CI 管道的多个阶段进行,一般我们会分阶段运行测试,并在每一步后提供结果。

常见的 CI 测试工具/平台有:

最后

前面俺也提到了,国内有不少公司都不太注重“测试”,更有甚者,直接不招聘测试人员。而且据我观察,越差的公司/团队,越是这样,这是对自己的水平有多放心呢?虽然是任何人都无法避免 bug,但能及时发现并修复总是好事儿吧,在优秀的团队里面做事,共同努力才是最好的结果,不是么?

在我刚参加工作时,同样也不怎么了解这一块,曾经也在没有测试、不写单元测试的公司带过,其中的风险可想而知。不是说做好测试线上就一定没问题,而是好的测试,能够最大程度上避免线上问题,甚至能让你提前准备针对线上问题的预案。曾经我想学好单元测试时,找不到地方学,因为公司没人写,问朋友也不会。最终还是去看书——《Java 测试驱动开发》,虽然这本书并不是 100 % 读完和消化完了,但是它的思想,深深影响着我。。。

还有个怪事儿,一般我学习一个东西怎么写的时候,因为担心自己想出来的方式太差,就喜欢去 GitHub 上面找一些看上去不错的项目,研究人家的代码实现。但唯独这一次,可能是个例外,我发现很多的“系统”项目,比如 XX 管理系统、XX 商城,几乎都没写单元测试🥲甚至是一些商业公司做的开源项目也是。当然,最后还是找到一些优秀的团队的项目,看着人家的代码学了学单元测试怎么写,而且很多都是真实场景实践出来的。 像者优秀的人学习,自己也能变好,虽然自己很多地方经验也有所欠缺,但只要不断学习、踩坑,相信我的代码可靠性也会越来越高的😊

珍珠之歌——我的2021总结

这便是你长路的纪行,这便是你们的珍珠之歌。

题记

这篇年终总结是 2021 年的,当你看到这篇文章的时候,说明 2021 年已经过去了。在这一年经历了许多,也成长了许多,但毫无疑问,今年是我技术能力【跃迁】最大的一年。但是不管怎样,俺都得认真做好总结。

原本标题应该叫做《时间与人生——我的2021总结》的,但是原神实在是太好玩了,所以就用了游戏里的【珍珠之歌】来命名了。

The unexamined life is not worth living. 未经反思自省的人生不值得去过。

回顾

👉 我的 2020 年终总结

2021 年的年度规划

  • Java,本职工作,可以针对集合、多线程、IO、jvm 等作为切入点深入学习。
  • 深入学习Spring、SpringCloud、MySQL、Redis和Elasticsearch(看着有点多😅)。
  • 入坑 Rust 或 Go。
  • Vue / JavaScript / CSS 的学习,起码得能写点有模有样的东西,虽然是 Java 程序员,但是前端不会点还是不太行。
  • 坚持锻炼身体(以跑步为主)。
  • leetcode 坚持刷题,希望不要碰到困难就停住了。
  • 不仅要有输入,也要有持续的输出。
  • 写一款自己的主题或 web 项目。
  • 成立一个小的开源开发团队,虽然技术目前不算好,但是一步一步走,总有一天会变好!

今年没有入坑 Rust 和 Go,Go没学完,算不算入坑。不过我倒是入坑了 Python,原因就是我需要用 Python 来帮我做一些事情。至于刷题,今年确实没有去 leetcode 刷,原因很简单,就是没空。对于目前的我来说,学习的重心不是在那些算法题。

📚 我的书单

这里统计一下今年阅读过的书单,当然,并不是所有书都读完了,有些书是在读状态,所以,你可能会在我的 2022 年终总结里面再次看到相同的书:

技术类:
《Python编程:从入门到实践》——读完
《Head First Go语言程序设计》——在读
《MySQL必知必会》——读完
《凤凰架构:构建可靠的大型分布式系统》——在读
《重学Java设计模式》——在读
《深入浅出Docker》——在读
《Effective Java》——在读
《Spring实战》——读完
《SpringBoot实战》——读完
《Spring微服务实战》——读完
《Spring Cloud Alibaba微服务原理与实战》——读完
《Spring Security实战》——读完
《数据密集型应用系统设计》——在读
在线电子书:
《现代JavaScript教程》——在读
《Serverless 架构应用开发指南》——在读
《Docker 从入门到实践》——在读
其它:
《黑客与画家》——在读
《明朝那些事儿4:粉饰太平》——读完
《明朝那些事儿5:帝国飘摇》——读完
《明朝那些事儿6:日落西山》——读完
《明朝那些事儿7:大结局》——读完
《知行合一王阳明》——在读

大伙儿可能发现了,今年我除了读技术书之外,还读了一些其它类别的书籍。主要是我觉得,我的人生不应该只有技术,还得多看看不同的书,扩展我的视野。当然,这几本书对我也产生了一定的影响。

👨‍💻 我的数字生活

开源项目

今年也做了一些自己的开源项目,做这些项目的目的,就是以【项目驱动学习】。对于这些项目,我是通过看书、查阅文档和资料,来进行知识储备的。也正好能按照我规划的学习路线去学新东西,整理笔记、总结。虽然项目可能压根就写不完,但是对我来说,做这件事是比较有意义的。

如果你想查看更详细的面板,可以访问 GitHub Wrapped

Readme Card

虽然俺现在还写不出能让很多人使用的优秀开源项目,但是我相信,随着时间的积累、技术的提升,总有一天我能开发出好项目。毕竟咱还年轻,而且 20~30岁,是知识储备的黄金年龄,对吧?

云服务

今年还完善了一下个人云基础设施,把各种免费和付费的服务利用到了极致,不仅能部署我的项目,还能帮我跑很多东西,极大地丰富了我的数字生活。

我的现实生活

游玩记录

今年到杭州来工作了,也去过不少好玩的地方,当然,西湖也是去过的。在上家公司上班的时候,中午吃完饭可以直接在西湖逛逛。

我整理了一些照片,你可以在我的相册看看。

参加线下活动

圣诞节当天,参加了 Google Devfest 2021 HangZhou 线下小沙龙,本来是一次大活动的,因为疫情管控的原因,改成小沙龙了。

这样的小沙龙很有意思,因为人数不多,但实际上你同 GDE 的交流机会就变多了,还有精致的下午茶,所以机会是挺难得的。

买了一些东西

仙剑奇侠传七发布的时候,入手了实体豪华版。

入手了 GSAS 仙剑奇侠传 赵灵儿 25 周年纪念手办😊

注:手办要明年5月发货,这里用的宣传图片。

考虑到 OLED 对眼睛造成的不适,于是入手了 kindle。

人生

在任何结果未 100% 确定的时候,我都不想透露过程。毕竟,没人会在意过程,大家都只会关注结果。没有结果的努力,终究只是在感动自己。当然,来自他人重复的询问也是让人很烦恼的,我实在是难以忍受机械式的给不同的人回答相同的问题了。

看看这一年

年初的时候,就从武汉的公司辞职了,因为担心疫情严重回不了家,而且打算年后从武汉跳到杭州找工作,于是就。。。实际上是在家里休息了一个月的时间,但是过的却很快乐。

年后在 2 月下旬的时候,就来到杭州了。这段时间实际上是没有好心情的,每天都在为面试而感到紧张,有许多不好的结果,但是也总结了很多面试的经验。这可能跟我投简历的方式有关吧,因为高质量的面试占比其实很低,很多只是为了刷 KPI,更有甚者,问的问题他自己都答不上。所以还是很感谢有部分面试官给我带来了高质量的面试,并不是说要问的多难或者多简单,而是能根据面试者面试的岗位、面试者的简历、以及公司招人的侧重点,给出针对性的问题,让双方都愉快。

这一年在杭州经历了 3 家公司,最短的一个星期,最长的就是我现在这家了。今年经手的项目,说得过去的,也有 5 个了。其中一个日请求数能达到 500w,另一个是我在负责的微服务项目,这些也都算是一段不错的经历吧。

从去年毕业,到现在也有一年半了,一路过来挺不容易。学历低确实是会在面试时受到不少歧视,所以咱只能努力提升自己啦!今年也报考了非全日制专升本,专科学历确实会让人错过很多机会,所以希望能顺利拿到毕业证吧,加油!

未来

我的未来会是个什么样子呢?今年和不少人交流了他们的成长路径和学习方法。在 Devfest 小沙龙也同 GDE 沟通过,听了下别人是怎么做的,我打算吸取他人好的学习方法,结合自己的经验,按照自己的规划走下去。

2022 年,我希望在技术上继续提升,继续深入学习 Java 语言以及 Spring 全家桶。学会 React 和 TypeScript,以及周边工具。继续学习 Python,因为我需要 Python 帮我完成一些事情,我所掌握的脚本语言中,它是最合适的。当然,Serverless 有空的话也会学。

2022 年,我想再买一台笔记本,当然,Windows 笔记本已经有了,它承担了我大部分任务,包括游戏和工作。所以我会考虑 14 寸的 MBP,虽然我不怎么喜欢电脑屏幕上的刘海,以及 ARM 芯片,所以会观望一下。

2022 年,我也想去旅游一次,哪怕是一个人去,我想去外面走走。

2022 年,我想买一台自己的相机,可以拍照和 Vlog,记录下我这简单又平凡的生活。

2022年,希望能脱单!

2022 年,希望能平安健康的度过!

最后,借用下去年的一句话:

我希望 2022 年能沉下心来多读书,避免直接照搬别人的答案,而应该结合书本中成体系的知识,通过自己的独立思考得出自己的答案。对编程保持足够的热情、足够的动力、足够的耐心,最重要的是坚持下去!

感谢你能看到这儿,新年快乐,在此献上我最忠心的祝愿😊!

站点文件基本配置

刚接触Hexo的你,是不是对站点配置文件_config.yml一脸的问号呢?没事,这篇文章可以帮助你轻松阅览站点配置文件,让你快速上手!

简介

总所周知,在Hexo静态博客本地配置中,有两个重要的配置文件,分别是:

  • 位于根目录下的站点配置文件_config.yml

  • 位于根目录/theme/你的主题下的主题配置文件/theme/<你的主题名称>/_config.yml

当然,基本熟悉的小伙伴是不会弄混的,刚开始的时候可能会弄错。

源码

下面简单列举了一些站点配置文件的源码,方便快速上手:

# Hexo 站点配置文件
## 官方说明文档: https://hexo.io/docs/configuration.html
## GitHub源码: https://github.com/hexojs/hexo/
# 网站基础设定
title: 生如夏花 # 网站标题
subtitle: www.zhuimeng.online # 网站副标题
description: 追逐梦想! # 网站描述:建议描述:网站介绍或者座右铭
keywords: 博客,Hexo,黑苹果,Linux # 关键词
author: Bess Croft # 站长信息
language: zh-CN # 网站语言:查询主题文件下的language文件夹查阅支持语言列表再进行更改
timezone: Asia/Shanghai # 网站时区
# 头像
avatar: /uploads/avatar.jpg
# 网址信息
## 如果您的网站存放在子目录中,例如 http://yoursite.com/blog,则请将您的 url 设为 http://yoursite.com/blog 并把 root 设为 /blog/。
url: https://blog.52bess.com # 网址
root: / # 网站根目录
permalink: :title.html # 文章的 永久链接 格式
permalink_defaults: # 永久链接中各部分的默认值
# 目录:如果您刚刚开始接触Hexo,通常没有必要修改这一部分的值。
source_dir: source # 资源文件夹,这个文件夹用来存放内容。
public_dir: public # 公共文件夹,这个文件夹用于存放生成的站点文件。
tag_dir: tags # 标签文件夹
archive_dir: archives # 归档文件夹
category_dir: categories # 分类文件夹
code_dir: downloads/code # Include code 文件夹
i18n_dir: :lang # 国际化(i18n)文件夹
skip_render: README.md # 跳过指定文件的渲染,您可使用 [glob 表达式](https://github.com/isaacs/node-glob)来匹配路径。
# 文章
new_post_name: :title.md # 新文章的文件名称
default_layout: post # 预设布局
titlecase: false # 把标题转换为 title case
external_link: true # 在新标签中打开链接
filename_case: 0 # 把文件名称转换为 (1) 小写或 (2) 大写
render_drafts: false # 显示草稿
post_asset_folder: true # 启动 [Asset](https://hexo.io/zh-cn/docs/asset-folders) 文件夹
relative_link: false # 把链接改为与根目录的相对位址
future: true # 显示未来的文章
highlight: # 代码块的设置
enable: true
line_number: true
auto_detect: true
tab_replace:
# 主页设置
index_generator:
path: '' # 博客索引页面的根路径。
per_page: 10 # 每页显示的帖子。(0 =禁用分页)
order_by: -date # 排序。(默认情况下按日期降序排序)
# 分类 & 标签
default_category: uncategorized # 默认分类
category_map: # 分类别名
tag_map: # 标签别名
# 日期 / 时间格式
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
date_format: YYYY-MM-DD
time_format: HH:mm:ss
# 分页
per_page: 10 # 每页显示的文章量(0 = 关闭分页功能)
pagination_dir: page # 分页目录
# 扩展
## 插件: https://hexo.io/plugins/
## 主题: https://hexo.io/themes/
theme: next #主题选择
# 部署部分的设置
## 文档: https://hexo.io/docs/deployment.html
deploy:
type: git
repository: git@github.com:<Github账号名称>/<Github账号名称>.github.io.git # 仓库ssh
branch: master #分支选择
post_end_tag:
enabled: true # 是否开启文末的本文结束标记
icon: paw # 结束标记之间的图标
# 看板娘
live2d:
enable: true
scriptFrom: local
pluginRootPath: live2dw/
pluginJsPath: lib/
pluginModelPath: assets/
tagMode: false
debug: false
model:
use: live2d-widget-model-koharu
scale: 1
hHeadPos: 0.5
vHeadPos: 0.618
display:
superSample: 2
position: right
width: 150
height: 300
hOffset: 0
vOffset: -20
mobile:
show: false
scale: 0.5
react:
opacityDefault: 0.7
opacityOnHover: 0.2
# 豆瓣页面
douban:
user: 195767035
builtin: true
book:
title: '我的书单'
quote: '看书很慢,但都是值得的'
movie:
title: '我的电影'
quote: '最佳的娱乐方式'
game:
title: '我的游戏'
quote: '最佳的娱乐方式'
timeout: 10000
#
archive_generator:
per_page: 20
yearly: true
monthly: true
tag_generator:
per_page: 10
# Extensions
plugins:
hexo-generator-feed
#Feed Atom
feed:
type: atom
path: atom.xml
limit: 20
# 自动生成sitemap
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml

黑苹果教程

写在前面

这可能、应该、也许是我写的最后一篇黑苹果相关文章(至少在我买新电脑之前),以后精力全部放在学习上,建议后来想要研究黑苹果的同学们早日弃坑,把时间放在更宝贵的事情上吧。经过一些调查,很多同学们装黑苹果的原因无非就是:折腾,当然也有其它的回答。但是,折腾的同时也确实可以学到很多东西。我想说的是,虽然黑苹果非常适合爱折腾的你,但是,折腾明白之后、或者是折腾不来,那么还是劝你早日退坑。。。

配置一览表

OMEN by HP Laptop 15-ce0xx HP 暗影精灵3
BIOS版本 F.18-11/09/2018
CPU i7-7700HQ
显卡 nVidia GTX 1050
声卡 ALC295
硬盘 HP SSD EX950 512G、HGST 1T

如果你的电脑和我同配置的话,EFI文件可以直接用我的安装使用,配置相仿的不可以直接使用,自己可以根据我的配置按需调整。但是请注意,我GitHub里的并不是完整的EFI,但是足够跟我同配置的同学安装使用了。

安装准备

下载

相关的文件我都在我的GitHub发布了,打不开或者下载不来的,自己多研究研究吧,一切随缘!!!(当然这个项目可能还不太完善,我会慢慢整理的,避免大家走弯路!当然,你有什么好资源,也可以让我上传,毕竟这是个开源项目!仅限于学习研究使用!),没错,为了方便大家下载,我把文件打包了,不打包有的小伙伴下载不来。👉GitHub

一些说明

  • 声卡正常,键盘可以调声音
  • 摄像头正常
  • 触摸板正常
  • 睡眠和唤醒正常,合上盖子再打开也正常,我不知道白苹果是怎样的,但是我试了很多次,没发现问题。
  • 电池正常
  • 有线网卡正常
  • 亮度正常,但是不能用键盘调整,在设置里面可以调整(我得再去爪巴帖子了😓
  • 独显因为不能驱动,所以屏蔽
  • 蓝牙
  • WiFi :(

BIOS设置

HP的BIOS建议:

  • 关闭安全模式

其它品牌建议还要:设置为AHCI模式

嗯~ o( ̄▽ ̄)o,有空再写,不着急。。。

准备

在开始前,我们建议你准备一个最好大于8G的U盘、一台电脑(不熟练的人建议2台)、一个具有你Windows系统恢复介质的U盘(因为装黑苹果导致Windows挂掉的人不在少数),一个用来备份的移动硬盘(如果你没有需要备份的文件请随意)。

  1. 原版镜像,注意是原版的加工封装的OS镜像,带不带Clover引导无所谓,新手建议带上,那样就不用自己配置了!
  2. U盘烧写工具,有很多,我用的TransMac,所以建议使用TransMac。
  3. 硬盘管理工具,这个当然是DG了!
  4. EFI启动引导项管理工具,推荐EasyUEFI或者UEFIBCD。
  5. 强制性要求:主板必须支持UEFI,这篇文章是适用于UEFI启动的,如果不是的话,你看这篇文章也没意义。
  6. 硬盘为GPT格式。
  7. 给黑苹果的EFI分区一定要大于200M!!!

安装MacOS

开机按F9进入Boot Manager引导管理,选择你制作的那个U盘,然后回车!

然后进入Clover主菜单

移动光标到Boot OS X Install from ***回车,如果无法进入安装界面,需要打开啰嗦模式进行排错,不过新手可能看不懂,但是也要拍照,给知道的人帮忙看看。

引导MacOS

基本上就是图中的样子啦!稍等片刻。具体时间决定于你的配置,耐心等待一小会儿进入安装程序界面。

语言选择

建议选择简体中文哦!😋

点击下一步,出现macOS实用工具界面,选择磁盘工具

进入磁盘工具之后,选择显示所有设备:

选择你在Windows下事先创建好,准备给macos用的那个分区,点击抹掉按钮,选择默认的Mac OS扩展(日志型),将名称修改为你自己喜欢的名字即可,点击抹掉按钮。

之前专门强调了备份了的啊!!!千万注意!!!

如果这时候报错,是由于EFI分区尺寸小于200MB而引起的抹盘失败的错误,甚至可能会导致后面的安装失败!!!

安装开始啦!

这个时候我们选择希望,哦不,是选择安装macOS

进入安装界面

下一步

选择继续,然后选择你才格式化了的硬盘。

在这期间,它会把USB安装盘上的安装文件预复制到要安装的系统分区里,这个过程在HP暗影精灵3上它跑得飞快(我放在固态上了),数据复制完后,它会自动重启

其实我感觉安装,和安装完了的设置,压根没必要写啥教程,因为你能进入这个界面的话,说明你的能力足够你一个人完成。

设置向导

不多说废话了,也不放图,简单粗暴的列几条建议:

  • 首先会让你选择国家,在这一步我选择中国!
  • 设置键盘,根据自己的习惯选择
  • 如果是新安装,建议不传输信息到这台Mac
  • 数据恢复,嗯,跳过吧
  • Apple ID登录,建议进入系统后再登录
  • 创建用户,这一步很简单
  • 反正有啥要你同步的一律先不干,也不要连接到互联网,建议进入系统后再慢慢设置。

安装完成后

千万别以为这样就完事儿了,Windows安装完之后都还需要联网安装更新呢,后面更艰巨的任务在等着你,小老弟🤣

挂载EFI分区

首先你肯定得把你U盘里的EFI文件弄到电脑上的EFI分区里去,如果你不愿意干这一步,那么你每次启动MacOS都将插上U盘。虽然我有一段时间这么干过,因为我觉得不插上U盘的时候,感觉MacOS系统就不存在了一样,要用的时候直接插上U盘即可!如果你想将U盘里的EFI复制到磁盘的EFI分区里,却苦于找不到看不见EFI分区,这个时候是该让diskutil登场了。

查看磁盘分区表:

diskutil list

挂载磁盘EFI分区:

sudo diskutil mount <这里填你的分区,比如:disk0s1,具体的查看你的磁盘分区表>

挂载U盘EFI分区:

sudo diskutil mount <这里填你的分区,比如:disk0s1,具体的查看你的磁盘分区表>

打开Finder,注意后面有个.

open .

左侧会显示挂载了两个EFI分区,将U盘EFI目录全部复制到磁盘的EFI分区即可。

合并EFI分区

这里有一点需要注意:如果之前安装过Windows系统的话,会存在EFI的目录,只是EFI的目录下面只有BOOT和Microsoft这两个目录,如果希望添加macOS的Clover引导的话,可以将USB的EFI分区里面的EFI目录下面的CLOVER复制到磁盘里的EFI目录下,也就是执行的是合并的操作,让EFI同时支持WINDOWS和macOS的引导.千万不要全部复制,否则有可能造成EFI无法启动Windows.

复制EFI分区

如果磁盘上的EFI分区里为空的,可以直接将USB的EFI分区下面的EFI目录直接复制到磁盘上的EFI分区里.

Windows下的骚操作

挂载EFI分区

Windows操作系统下面,打开cmd窗口,输入命令:

diskpart
list disk # 磁盘列表
select disk n # 选择EFI分区所在的磁盘,n为磁盘号
list partition # 磁盘分区列表
select partition n # 选择EFI分区,n为EFI分区号
set id="ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" # 设置为EFI分区
assign letter=X # x为EFI分区盘符

您可以重复输入命令同时挂载USB的EFI分区和磁盘的EFI分区 打开资源管理器,会出现一个盘符为X的磁盘,格式化为fat32格式,将USB的EFI分区下面的EFI目录复制到安装磁盘的EFI分区下。

合并EFI分区

这里有一点需要注意:如果之前安装过Windows系统的话,会存在EFI的目录,只是EFI的目录下面只有BOOT和Microsoft这两个目录,如果希望添加macOS的Clover引导的话,可以将USB的EFI分区里面的EFI目录下面的CLOVER复制到磁盘里的EFI目录下,也就是执行的是合并的操作,让EFI同时支持WINDOWS和macOS的引导.千万不要全部复制,否则有可能造成EFI无法启动Windows.

复制EFI分区

如果磁盘上的EFI分区里为空的,可以直接将USB的EFI分区下面的EFI目录直接复制到磁盘上的EFI分区里.

利用EasyUEFI来挂载

什么?看不懂这些指令,怕出错?我懂你!你可以在Windows系统下利用诸如EasyUEFI等工具来操作。

我们打开下载好的diskgenius工具

EFI分区的文件一般是这样的

打开EsayUEFI,点击中间的绿色加号,进入添加引导项的页面,选择"Linux或其它操作系统",并且在Description这一项写入这个引导项的名字(名字可以随便乱取,但是别忘记!)。然后在下面的硬盘选择区域选择一个你自己新建的ESP分区,然后点击下方的Browse浏览文件。

然后选择自己配置好的EFI中的CLOVERx64.efi这个文件以完成添加。

然后回到工具的首页,将该引导项置顶(置不置顶看你自己选择了,想要开机可以选择双系统就置顶,想要开机直接进入Windows,就放在Windows Boot Manager后面)

到这里就大功告成啦!

EasyUEFI报错
  • 这个可能是因为BIOS设置问题,如果加了BIOS密码,会报这个错误。还有可能就是EFI分区没有正常挂载的原因。遇到这个问题,有的时候照样能够添加进去引导项,但是无法移动引导项的顺序。这样的话,你可以先添加,再进入BIOS设置引导顺序,或者是直接在BIOS里面添加启动项。如果EasyUEFI完全没有作用,你可以尝试进入PE卸载ESP分区重新启动或是先备份系统的EFI分区,然后使用DG将原本的EFI分区删除,重建以后重启即可。
  • 可能是当前版本的EasyUEFI出现了问题、或者是你下的有问题、或者是当前版本与你的电脑不兼容
利用BOOTICE
  1. 打开BOOTICE软件,选择物理磁盘,选择欲操作的目标磁盘,点击分区管理,弹出分区管理的窗口,点击分配盘符,为ESP分区分配一个盘符,点击确定
  2. 选择UEFI,点击修改启动序列,点击添加按钮,菜单标题填写:CLOVER,选择启动文件,在打开的窗口里选择ESP分区下的目录\EFI\CLOVER\CLOVERX64.EFI,点击保存当前启动项设置

下载链接

迅雷离线下载:点击下载感谢@难忘情怀提供下载资源

http下载链接:点击下载感谢@难忘情怀提供下载资源

百度网盘:点击链接 接头暗号:s68r MD5 (macOS Mojave 10.14.3(18D42) Installer with Clover 4859.dmg) = 450c55e5c5d3f4bfae6bb55ff2a33aea

EFI下载/更新

点击这里进入魔法门

特别鸣谢

@原味菠萝 @黑果小兵 为本教程提供的的大力支持!

浅谈:强大的Hexo

什么是 Hexo?

Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

为什么要使用Hexo?

  • 买个服务器太贵,目前的服务器在阿里云,这配置,学生价便宜,那么以后呢?

  • 学习一下新东西,折腾折腾。主要还是学一学Git和GitHub的使用。

怎么搭建的?

  1. GithubPages

  2. GithubPages + 域名

    这个方案当然更好,好的域名方便记忆,买个便宜点的域名第一年也就10来块钱,一年换一个经济便宜,如果想长期做,那就一次性来个5年。

  3. CodingPages + 域名

    GithubPages 在国内较慢,百度不收录,而CodingPages 在国内外都比较快。

  4. GithubPages + CodingPages + 域名

    嗯。我采用的是方案四,这样可以保证更多的不同网络环境下都能访问,即使可能根本没人看。。。

难吗?

这个我不好说,毕竟每一个人不一样。但是我可以保证的是,只要你愿意折腾,哪怕你没有代码基础,你也能搭建出来。我目前接触了2种搭建博客的方式,第一种是阿里云买服务器,基于CentOS搭建的WordPress,是动态的。第二种就是这个由Hexo驱动的静态了,但是省钱啊,每年只用出域名的钱,你说香不香,但是优化还是要花费一番功夫的。当然第二种更简单。。。

自己买服务器搭建你可能要接触到CentOS、Apache、PHP、MySql、WordPress等等。使用Pages的话,可能要接触Node.js、Git、GitHub、Hexo。最好还是有一点前端基础,并不是说没有就弄不出来了,有的话可以节省你很多时间,更多的时候可能不至于让你的心态爆炸。

最后

Hexo 提供了快速方便的一键部署功能,让你只需要一条命令就能将网站部署到服务器上。如果有人愿意看的话,我会在后面的文章中详细讲述我是如何搭建的,从零到搭建完成的每一个详细步骤,争取让不懂的你,也能拥有一个自己的博客!还会总结一些我在使用过程中遇到的坑,以免大家掉进去。

❌
❌