the missing-semester笔记拥有一个目录下某个文件的写权限但是没有目录的写入权限的话，可以清空该文件内容分但是无法删除文件
问题的产生我的health-care健康饮食管理系统在使用过程中逐渐产生了一个问题,那就是随着用户摄入食物项目的添加,食物数目会变得更多用户需要寻找很久才能找到匹配的食物选项。同时由于页面简约性的要求，以及对于移动端设备支持的友好性方面考虑我想应该可以用一个类似计算机cpu调度方面的简单算法来解决这个问题。为了实现这一目标，我设计了一个基于频次和时间间隔的排序算法，使得推荐系统不仅了解用户的即时需求，也能通过历史选择为用户提供合理的推荐。算法的需求基于频次的考虑：如果你经常选择某个食物，系统会优先推荐它，因为频繁的选择暗示了你对这个食物的偏好。基于时间间隔的考虑：如果某个食物已经很久没有被你选中了，系统会降低它的推荐优先级，避免向你推荐那些你可能已经不感兴趣的食物。于是可以设计一个这样的函数：$$ \text{priority\_score} = \text{frequency} \times \left(1 + \frac{\text{time\_weight\_factor}}{\text{days\_since\_last\_selected} + 1}\right) $$公式的组成部分frequency（频次）：这是用户选择某个食物的次数。假设你频繁选择某个食物，它的频次就会较高。频次越高，意味着这个食物更符合用户的长期偏好，因此它对最终优先级的贡献也会越大。days_since_last_selected（自上次选择以来的天数）：这是当前日期与用户最后一次选择该食物的日期之间的天数差。这个数值越大，意味着食物越久未被选中。一般来说，如果一个食物长时间未被选择，我们可能希望它的优先级会降低（除非用户有意想要重新尝试的需求）。time_weight_factor（时间权重因子）：这个值决定了时间因素在最终优先级中的影响力。它是一个调整系数，影响时间间隔对食物优先级的贡献。数值越大，表示时间的影响越大，即食物选择的时间间隔对优先级的影响会更强。公式的逻辑:$$ 1 + \frac{\text{time\ weight\ factor}}{\text{days\ since\ last\ selected} + 1} $$这一部分是计算时间间隔对优先级的影响。假设食物的选择频次是固定的，这一项会根据食物的上次选择时间进行调整。$$ \text{days\ since\ last\ selected} + 1 $$确保即使食物的选择频次是近期的，也不会造成除零错误。time_weight_factor 放大了时间间隔的影响，使得长期未被选择的食物得分明显降低。乘以 frequency：最后，我们将频次与时间因子相乘，最终的优先级分数既考虑了食物的选择频次，也考虑了其历史选择的时间间隔。设置合适的 time_weight_factor 取决于你的应用场景以及用户的行为特征。以下是不同情境下的建议：注重近期行为的场景如果你希望系统更重视用户近期的选择习惯，并且优先推荐用户最近选择的食物，那么可以选择较小的 time_weight_factor。例如：适合值：5-15 效果：时间间隔对优先级的影响较小，频次的影响占主导地位，推荐频繁选择的食物。用户的历史选择不久的食物将优先推荐，忽略较久未选择的食物。注重长期偏好的场景如果你希望推荐系统更注重用户的长期偏好（例如，帮助用户重新开始选择长期未选过的食物），可以将 time_weight_factor 设置得较大。这样，时间间隔的影响会显著地增加，较久未选择的食物将得到更多的优先推荐。适合值：20-50。效果：时间间隔对优先级的影响增大，推荐系统会更倾向于推荐久未选择的食物，即使频次较低。平衡近期和长期行为的场景如果你希望在推荐中平衡近期选择与长期偏好的影响，可以选择一个中等的 time_weight_factor，例如 10-20。这样既能考虑用户最近的选择行为，也不会忽略那些久未选择的食物。适合值：10-20。效果：推荐系统在近期行为与长期偏好之间找到一个平衡，频次和时间间隔的影响都得到合理的考虑。例子：优先级得分计算假设我们有两个食物项 A 和 B，我们将根据以下公式来计算它们的优先级得分：食物 A：frequency = 10days_since_last_selected = 5time_weight_factor = 10计算公式：$$ \text{priority\_score\_A} = 10 \times \left(1 + \frac{10}{5 + 1}\right) = 10 \times \left(1 + \frac{10}{6}\right) = 10 \times 2.6667 = 26.67 $$食物 B：frequency = 5days_since_last_selected = 30time_weight_factor = 10计算公式：$$ \text{priority\_score\_B} = 5 \times \left(1 + \frac{10}{30 + 1}\right) = 5 \times \left(1 + \frac{10}{31}\right) = 5 \times 1.3226 = 6.61 $$结果分析：食物 A 的优先级得分为 26.67，食物 B 的优先级得分为 6.61。尽管食物 B 的选择时间间隔较长，但因为食物 A 的选择频次较高，所以它的优先级得分更大。通过这个例子，我们可以看到，优先级得分不仅考虑了用户过去的选择频次，还考虑了时间因素，从而可以更好地平衡用户的长期偏好和即时需求。总结用户偏好动态调整饮食偏好会随着时间变化，但用户对特定食物的频繁选择也反映了偏好。基于时间和频次的优先级算法可以结合用户的选择频次和时间衰减，更贴近他们当前的饮食习惯。在该算法下，用户最近选择的食物优先级更高，但不会完全忽视过去的偏好记录。避免频次累积带来的偏好失真简单的频次统计会导致一些被高频次选择过的食物始终在推荐前列，即使用户不再偏爱它们。时间加权可以很好地解决此问题，因为每次用户选择食物时，都会根据距离上次选择时间的远近动态调整优先级，从而更加灵活。兼顾用户的饮食多样性当用户尝试新食物或一段时间未选择某食物时，优先级会自动下调，让用户有机会接触到更多不同的食物。这种机制有助于引导用户保持均衡饮食。实现难度适中基于时间和频次的优先级算法实现起来相对简单，只需在数据库中多存储一个“上次选择日期”，并在推荐时加权计算。相比LRU缓存算法等实现逻辑更简单，对系统的性能要求也不会过高。实现代码# user_item_frequency表 CREATE TABLE IF NOT EXISTS user_item_frequency ( user_id INTEGER, item_id INTEGER, frequency INTEGER DEFAULT 1, last_selected DATE, PRIMARY KEY (user_id, item_id), FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (item_id) REFERENCES intake_items(id)) # intake_items CREATE TABLE IF NOT EXISTS intake_items ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, calories_per_unit REAL NOT NULL, pending_name TEXT, pending_calories_per_unit REAL, is_changed INTEGER NOT NULL DEFAULT 0, is_approved INTEGER NOT NULL DEFAULT 0) # 排序算法获取食物列表 def get_priority_sorted_items(user_id, time_weight_factor=10): conn = get_db_connection() cursor = conn.cursor() # 获取用户的所有食物频次记录 cursor.execute(''' SELECT item_id, frequency, last_selected FROM user_item_frequency WHERE user_id = ? ''', (user_id,)) items = cursor.fetchall() priority_items = [] for item_id, frequency, last_selected in items: # 将 last_selected 从字符串转换为 datetime.date 对象 last_selected_date = datetime.strptime(last_selected, "%Y-%m-%d").date() days_since_last_selected = (datetime.now().date() - last_selected_date).days priority_score = frequency * (1 + time_weight_factor / (days_since_last_selected + 1)) # 防止除零 priority_items.append((item_id, priority_score)) # 按优先级得分从高到低排序 priority_items.sort(key=lambda x: x[1], reverse=True) # 提取排序后的 item_id 列表 sorted_item_ids = [item[0] for item in priority_items] conn.close() return sorted_item_ids
正向代理（Forward Proxy）定义正向代理是一种位于客户端和目标服务器之间的代理，代表客户端向目标服务器发出请求，并将服务器的响应转发给客户端。[客户端] ----> [正向代理服务器] ----> [目标服务器]特点作用于客户端：客户端通过代理访问目标服务器，服务器不知道客户端的真实IP。隐藏客户端信息：可以帮助客户端隐藏其真实IP地址。突破访问限制：常用于访问被限制的网站（如翻墙）。典型应用场景绕过网络审查或防火墙。提升客户端隐私，隐藏其真实IP地址。提供缓存功能，加快客户端的访问速度。Nginx 正向代理配置示例server { listen 8888; # Nginx 监听的端口 location / { # 代理客户端请求到目标服务器 proxy_pass http://$http_host$request_uri; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }在该配置中，Nginx 代理客户端的请求到目标服务器。客户端可以通过代理访问任何目标地址。反向代理（Reverse Proxy）定义反向代理是位于客户端和服务器之间的代理，代表服务器接收客户端的请求，并将其转发给内部真实服务器。对客户端而言，反向代理就是目标服务器。[客户端] ----> [反向代理服务器] ----> [后端服务器1] [后端服务器2] [后端服务器3]特点作用于服务器端：客户端只知道代理服务器，并不知道后端真实服务器。隐藏服务器信息：可以隐藏后端服务器的IP地址和架构，提升安全性。负载均衡：可以将请求分发给多个后端服务器，提升系统的性能和可用性。缓存功能：反向代理可以缓存后端服务器的响应，提高访问速度。典型应用场景负载均衡：分发流量到多个后端服务器。安全性：隐藏真实服务器，防止直接攻击。SSL 卸载：处理 SSL 加密，并将明文请求发送给后端服务器。静态内容缓存：缓存静态资源，减少后端压力。server { listen 80; server_name example.com; location / { # 代理请求到后端服务器 proxy_pass http://backend_server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }在该配置中，客户端请求 example.com，Nginx 将该请求代理到后端服务器 backend_server。客户端并不知道 backend_server 的真实信息。正向代理 vs 反向代理特性正向代理反向代理代理对象客户端服务器隐藏对象隐藏客户端信息隐藏服务器信息客户端角色知道自己在使用代理，主动选择代理服务器不知道自己在与代理服务器交互主要用途翻墙、访问受限资源、隐藏IP负载均衡、缓存、SSL卸载、安全性提升典型应用场景绕过防火墙，访问受限资源，隐藏客户端IP负载均衡、隐藏服务器、SSL卸载、缓存静态资源
写这篇文章之时恰逢中秋佳节之际，祝各位朋友中秋快乐！我的博客自从2022年就已经建好，但是基本没有写很多东西在上面，搭建之初只是为了方便而使用了gitalk来作为评论系统。但这个开源项目的评论是基于github的issue来实现，虽然数据也是存储在自己的仓库并且免费。但是由于github在国内的网络环境下时好时坏，大部分情况下无法正常加载。而从个人博客评论功能的需求出发我主要归结为以下两点：加载迅速，不因为没有科学上网工具而无法使用数据安全，也即数据自己可以操控在自己的存储系统里面最好支持匿名评论，因为我不想让别人看个blog还要进行繁琐的登录这个时候刚好看到了一个叫做Artalk的开源项目，使用go语言编写号称轻量便捷并且它还在正常更新，拓展性高，可以本地化部署，正好满足我的需求。部署环境:Ubuntu 22.04正确部署姿势artalk/artalk-go#### **域名解析** 到你域名解析供应商处添加Artalk的域名解析记录如 ```comment.example.cn```指向你的服务器地址 #### **nginx配置和安装ssl证书** 在nginx.conf里面添加如下server块:server { listen 443 ssl; server_name comment.nighterdream.cn; ssl_certificate /etc/letsencrypt/live/comment.nighterdream.cn/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/comment.nighterdream.cn/privkey.pem; # managed by Certbot ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'HIGH:!aNULL:!MD5'; ssl_prefer_server_ciphers on; location / { proxy_pass http://localhost:8081; # Artalk 运行的地址和端口 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }其中证书由Cerbot生成， 至于为什么要反向代理请看下面[曲折经历](#曲折经历) 1. 安装 Certbot 和 Nginx 插件 首先，需要安装 Certbot 和它的 Nginx 插件。如果你使用的是 Ubuntu 或其他基于 Debian 的系统，使用以下命令： sudo apt updatesudo apt install certbot python3-certbot-nginx2. 运行 Certbot 自动化命令 运行以下命令，Certbot 将自动为你的域名生成证书，并更新 Nginx 配置以启用 SSL： sudo certbot --nginx根据提示进行输入信息 3. 测试 Nginx 配置 证书生成并配置完成后，重新加载 Nginx 以应用更改：sudo nginx -tsudo systemctl reload nginx #### **Hexo配置** 以butterfly主题配置为例，打来主题配置文件_config.butterfly.yml找到评论配置部分修改以下内容artalk: server: https://comment.example.cn # 你设置的Artalk服务端域名 site: example # 在Artalk配置中设置 visitor: false option:记得把评论功能打开，并且切换成Artalk Comments System--------------------------------------comments: # Up to two comments system, the first will be shown as default # Choose: Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/Artalk use: # Valine,Disqus- Artalktext: true # Display the comment name next to the button # lazyload: The comment system will be load when comment element enters the browser's viewport. # If you set it to true, the comment count will be invalid lazyload: true count: false # Display comment count in post's top_img card_post_count: false # Display comment count in Home Page #### **Artalk配置** 这个使用就可以通过```https://comment.example.cn```访问Artalk的后台评论管理系统了 1. 设置Artalk后台管理员账号 虽然能够访问了却需要账号和密码，在Artalk容器部署端执行：docker exec -it artalk artalk admin[Artalk文档](https://artalk.js.org/guide/deploy.html) 2. 设置可信域 添加以下内容,实际就是设置请求头内容防止跨域问题产生 http://comment.example.cn 防止国产浏览器无法加载，请参看[国产浏览器的坑](#国产浏览器的坑) https://comment.example.cn 3. 配置站点 这里的站点要和docker run 里面的yoursite对应，同时也要和你的hexo 主题配置文件里的site对应 4. 根据自己配置灵活进行，建议开启验证码，防止匿名评论轰炸消耗服务器资源，[参考官方配置文档](https://artalk.js.org/guide/deploy.html) #### **总结** 完成以上操作之后就可以```hexo clean; hexo g; hexo d```来推送博文了 在配置Artalk过程中自己也是踩了很多的坑，局域网内证书注册，还有就是[国产浏览器的坑](#国产浏览器的坑),很多问题都是一开始没有发现，实际操作中才能认识到，特别是国产浏览器无法重定向，估计又是[C2C](https://en.wikipedia.org/wiki/Copy_to_China)(copy to China)的锅，希望官方能够改一改。很多问题也都是在官方文档和错误日志中找到答案和解决办法，看日志的能力也是得到了一次提升。 ## **曲折经历** #### **局域网的坑** 我的博客部署在一台阿里云的服务器上，它的容量很小，所以的构想是将Artalk部署在本地的物理主机上，然后通过frp穿透出去。可是这个想法是好的在实际操作过程中却发现了问题。 我的博客为了安全采用了https协议传输数据，但是Artalk默认使用http在我部署好了之后我发现无法正常加载博客评论，打开浏览器终端发现是由于https和http不匹配造成的。之后我仔细查阅了Artalk的官方文档里面写道： 可以开启ssl加密传输 加密传输 sslssl: enabled: true cert_path: '' key_path: ''你可以配置该项，让 HTTP 升级为 HTTPS，通过 SSL 协议加密传输数据。cert_path：SSL 证书公钥文件路径。key_path：SSL 证书私钥文件路径。你也可以直接反向代理 Artalk 本地服务器，然后在例如 Nginx 启用 HTTPS。这时候就存在问题了我的Artalk是通过docker部署的而在docker 容器内安装证书显然不是一个很好的选择，我就剩下了另一个选择就是通过nginx反向代理Artalk服务器，但是这个时候就又存在了一个问题，**本地局域网内的物理机如何申请证书？**因为我是采用frp实现内网穿透的，所以申请证书基本可以宣告破产。 之后我想了一个办法，那就是把我服务器上使用certbot申请的证书给复制到我的局域网内的物理主机上，可结果确是不行，浏览器提示证书和域名不匹配，无法加载远程服务器资源，所以之后我将Artalk又使用docker部署到了我的阿里云服务器，并使用cerbot申请了证书，使用nginx将artalk本来的http反向代理成https,这似乎所有问题都得到了解决了我的博客的评论可以正常加载了，直到我发现了一个国产浏览器的坑。 #### **国产浏览器的坑** **nginx设置了将http请求重定向到https时，国产浏览器无法生效** 我在博客评论系统部署好并测试好没有问题之后就可高枕无忧，专注到内容的书写上。可当我姐来我家，我让她用她手机访问我博客时却发现了问题，她使用手机的夸克浏览器没法加载评论，这个时候我没太放在心上，可能是一个概率问题。但后面我发了一篇博文到微信上，用微信自带的qq浏览器也提示评论加载错误我这个时候才意识到不是偶尔的问题，而确实存在bug，我本人一共使用三款浏览器分别是：firefox, chrome, edge测试都没有发现任何问题，这个时候我下载了一个QQ浏览器，这个时候提示跨域问题了。 这就让我很不解了我在Artalk(Artalk设置了另外的域名，博客的评论是从artalk的网址加载评论数据，所有需要跨站请求)里面设置可信域：```https://www.nighterdraem.cn, https://nighterdream.cn```。 因为只有国产浏览器才无法加载评论所以我询问了chatgpt为什么我的Artalk评论系统在国产浏览器中会遇到跨域问题，在edge和chrome中却能正常使用以下是我的nginx配置server { listen 443 ssl; server_name comment.nighterdream.cn; ssl_certificate /etc/letsencrypt/live/comment.nighterdream.cn/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/comment.nighterdream.cn/privkey.pem; # managed by Certbot ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'HIGH:!aNULL:!MD5'; ssl_prefer_server_ciphers on; location / { proxy_pass http://localhost:8081; # Artalk 运行的地址和端口 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }跨域问题（CORS，Cross-Origin Resource Sharing）在国产浏览器中可能会导致 Artalk 评论系统无法正常使用，而在 Edge 和 Chrome 中可以正常使用，原因可能与不同浏览器处理 CORS 的方式有关。以下是可能的原因和解决方案：可能原因国产浏览器的安全策略差异：国产浏览器（如 QQ 浏览器、360 浏览器等）有时会对跨域请求进行更加严格的处理，而国际浏览器如 Chrome 和 Edge 可能会对开发中的应用更宽容，特别是对于本地服务器或 HTTP 请求。CORS 头缺失：你的 Nginx 配置中没有明确设置 CORS 相关的响应头，这可能导致国产浏览器拒绝跨域请求。代理转发的 Headers 问题：Artalk 的跨域配置可能没有正确传递给浏览器。国产浏览器可能严格要求返回正确的跨域响应头。解决方案在 Nginx 中添加 CORS 头：你可以在 Nginx 的配置中添加允许跨域的响应头，确保浏览器能够正确处理跨域请求。你可以在 location 块中添加如下 CORS 配置location / {proxy_pass http://localhost:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 添加跨域响应头 add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header Access-Control-Expose-Headers 'Content-Length,Content-Range';}这将允许所有源对你的服务器进行请求。如果你想限制特定的源，可以将 Access-Control-Allow-Origin 的值替换为特定的域名。确保 Artalk 支持 CORS：检查 Artalk 的配置文件或后端设置，确保它支持跨域请求。Artalk 可能需要配置允许的 Origin，确保它支持通过反向代理的跨域请求。OPTIONS 请求的处理：有时候浏览器会发送预检请求（OPTIONS 请求）以确认服务器是否允许跨域访问。你可以在 Nginx 中为 OPTIONS 请求添加一个单独的处理：if ($request_method = OPTIONS) {add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; return 204;}检查浏览器控制台的错误信息：如果问题依然存在，可以在国产浏览器中打开开发者工具，查看具体的错误信息，确认是哪个请求遇到了 CORS 问题。通过添加这些 CORS 设置，应该可以让国产浏览器与 Edge 和 Chrome 一样正常访问你的 Artalk 评论系统。 我按照他的建议进行了更改，但之后我发现连edge和chrome都无法加载了，查看请求头：HTTP/1.1 200 OKServer: nginx/1.18.0 (Ubuntu)Date: Mon, 16 Sep 2024 09:44:16 GMTContent-Type: application/jsonContent-Length: 731Connection: keep-aliveX-Request-Id: 001151ae-c7f7-4002-945b-748a1af32112Vary: OriginAccess-Control-Allow-Origin: https://www.nighterdream.cnAccess-Control-Allow-Origin: https://www.nighterdream.cnAccess-Control-Allow-Methods: GET, POST, OPTIONSAccess-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,RangeAccess-Control-Expose-Headers: Content-Length,Content-Range问题出在了 **Access-Control-Allow-Origin的值出现了两次**```https://www.nighterdream.cn``` 所以连edge和chrome也无法打开，原因是我在artalk的可信域里面进行了配置（应用层），然后在nginx里面又进行了配置（代理层），所以Access-Control-Allow-Origin 也就重复了导致edge无法打开，但神奇的是国产浏览器又能打开评论了，之后我将nginx配置中恢复了原样取消手动设置请求头。 这个时候我打开了QQ浏览器的开发者控制台发现如下报错： Access to fetch at 'https://comment.nighterdream.cn/api/v2/conf' from origin 'http://nighterdream.cn' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.这就很奇怪了为什么是```http://nighterdream.cn```而不是我设置的可信域```https://nighterdream.cn``` 然后我就在QQ浏览浏览器的导航栏输入：```http://nighterdream.cn```来访问我的网站，正常情况下我设置了nginx的http重定向https,浏览器应该会自动将导航栏上的地址改成```https://nighterdram.cn```，但是QQ浏览器没有。之后我又测试了edge,chrome浏览器发现他们都能重定向到https所以能够加载评论。 而QQ浏览器，夸克浏览器移动端，微信浏览器为代表的国产浏览器没有重定向而是继续使用http来访问，这也就造成了请求头里的Access-Control-Allow-Origin字段值和Artalk后端的```https://nighterdream.cn```不匹配，所以才无法加载评论，而我将Artalk的可信域里面加入```http:nighterdream.cn```后问题也就迎刃而解。 ## **参考资料** [Artalk文档](https://artalk.js.org/guide/deploy.html) [Artalk自托管评论系统搭建与配置](https://www.richarvin.com/artalk-zi-tuo-guan-ping-lun-xi-tong-da-jian-yu-pei-zhi/#artalk%E5%8A%9F%E8%83%BD%E9%85%8D%E7%BD%AE) [跨源资源共享（CORS）](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS)
使用 CDN 提升网站速度与安全性：我的博客加速之路
随着网站的访问量增加，页面加载速度和服务器安全成为了我的首要关注点。为了确保用户有更好的访问体验，同时提升网站的安全性，我决定为我的博客搭建 CDN（内容分发网络）。在这篇推文中，我将分享 CDN 建设的基本步骤以及它带来的显著效果。什么是 CDN？CDN，全称为内容分发网络（Content Delivery Network），它的主要目的是通过分布在全球各地的服务器节点来缓存和分发内容，提升网站访问速度，并降低源服务器的负载。当用户访问网站时，CDN 会将用户的请求转发到离用户最近的 CDN 服务器节点。若 CDN 节点上已有缓存的内容，则会直接将内容返回给用户。如果没有缓存，CDN 会将请求转发给源服务器获取内容，并将其缓存以供下次使用。CDN 的引入流程引入 CDN 的过程涉及以下几个步骤：1. 域名解析和 DNS 配置首先，确保域名通过 DNS 正确解析到 CDN 的加速域名。在我的案例中，我的博客域名 www.exampleblog.com 被解析到了 CDN 提供的加速域名 exampleblog.cdnprovider.com。配置步骤：将 www.exampleblog.com 的 CNAME 记录指向 CDN 提供的加速域名 exampleblog.cdnprovider.com。确保所有访问 www.exampleblog.com 的请求都通过 CDN，而不是直接到达源服务器。2. Nginx 服务器配置CDN 会向源服务器请求内容，因此源服务器的配置也非常重要。我使用了 Nginx 作为我的服务器，并确保 Nginx 能够根据 CDN 的请求正确返回内容。Nginx 的配置中只需要处理来自 CDN 的请求，无需特别为 CDN 配置额外的域名。配置时，确保正确处理主域名和子域名，并为 HTTPS 提供支持。以下为我的配置文件user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { server { server_name www.exampledomin.cn exampledomin.cn www.exampledomin.org; location / { root /home/www/hexo; } listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/exampledomin.cn/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/exampledomin.cn/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } ## # Basic Settings ## sendfile on; tcp_nopush on; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; # gzip_vary on; # gzip_proxied any; # gzip_comp_level 6; # gzip_buffers 16 8k; # gzip_http_version 1.1; # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; server { if ($host = www.exampledomin.cn) { return 301 https://$host$request_uri; } # managed by Certbot if ($host = exampledomin.cn) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; server_name www.exampledomin.cn exampledomin.cn www.exampledomin.org; return 404; # managed by Certbot }} #mail { # # See sample authentication script at: # # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript # # # auth_http localhost/auth.php; # # pop3_capabilities "TOP" "USER"; # # imap_capabilities "IMAP4rev1" "UIDPLUS"; # # server { # listen localhost:110; # protocol pop3; # proxy on; # } # # server { # listen localhost:143; # protocol imap; # proxy on; # } #} 3. CDN 处理流程当用户访问 www.exampleblog.com 时，CDN 会首先检查是否有缓存的内容。如果有，CDN 将直接返回给用户；如果没有，CDN 会向我的 Nginx 源服务器发起请求，然后将响应缓存并返回用户。这大大减少了源服务器的直接负担，同时提升了访问速度。4. DDoS 防护与安全性提升通过使用 CDN，还为网站提供了额外的安全性。因为 CDN 服务器接管了用户的请求，用户无法直接获取到源服务器的 IP 地址，这让源服务器免受直接攻击，尤其是 DDoS 攻击。此外，CDN 通常提供基础的 DDoS 防护功能，帮助我应对大流量攻击。虽然流量峰值可能会导致 CDN 费用上升，但相比于直接攻击源服务器，风险和损失都得到了很大程度的缓解。5. 总结一个用户访问博客经过的完整流程应该如下：用户访问 www.exampleblog.com用户在浏览器中输入你的博客网址并发起访问请求。DNS 解析 www.exampleblog.comDNS 服务器将域名解析为 CDN 提供的加速域名。CDN 节点检查缓存CDN 节点检查是否已经缓存了用户请求的内容。CDN 返回缓存内容如果缓存命中，CDN 直接将缓存内容返回给用户。CDN 转发请求到源服务器如果缓存未命中，CDN 将请求转发到源服务器（你的 Nginx 服务器）。Nginx 源服务器处理请求源服务器处理请求，生成博客页面内容。返回博客内容给 CDN源服务器将生成的内容返回给 CDN。CDN 缓存内容CDN 将从源服务器获取的内容进行缓存，以便下次请求时可以直接返回。并返回内容给用户CDN 将内容返回给用户的浏览器。用户成功加载博客页面，用户在浏览器中成功加载并查看博客页面。通过引入 CDN，我的博客访问速度显著提升，尤其是在不同地区的访问效果更为明显。同时，源服务器的 IP 地址得到了保护，避免了潜在的安全威胁。CDN 在以下几个方面帮助提升了网站性能和安全性：加速用户访问：无论用户在哪个地区，都能快速加载页面。减轻源服务器压力：CDN 缓存有效地减少了对源服务器的请求频率。提升安全性：隐藏源服务器 IP 地址，并提供基础的 DDoS 防护。如果你也在寻找提升网站速度与安全的方式，CDN 是一个非常值得考虑的方案！值得一提的是需要关注自己的cdn配额，如果遭遇了ddos攻击或者是大量的访问可能会造成一些cdn费用的问题。参考资料Hexo博客搭建教程，及阿里云服务器部署实战CDNNginx 极简教程什么是CDN安全防护
关于知识图谱的复习简单了解基于关键词匹配的传统搜索引擎，是将匹配到关键词后再把信息展现出来。如果把信息的形式进行转换，例如将里面的人物、地点、时间等信息抽取出来，构建一个知识图谱的结构，就可以将“詹姆斯瓦特的校友是谁？”等问题的答案推理出来。知识图谱实现了从原来的关键字匹配、内容匹配的方式，转变为对信息的推理、对信息的追溯这种方式。知识图谱本质上是基于图的语义网络，表示实体与实体之间的关系。与传统数据库相比，Neo4j的数据结构更加自由Node(结点)：含有：Perpority Label用于通过属性存储数据，就比如简单的社交图name:Emil这个键值对就存储了这个人的名字，from: Sweden存储了来自那里Lable: Person表明了这个节点的实体是一个人可以通过Label表明属于同一个群体每一个实体可以包含相同的属性，也可以光有单独的属性Relations(关系):Emil knows Johan and Ian.Johan knows Ian and Rik.Rik and Ian know Allison.关系必有方向也可以有值Emil has known Johan since 2001.Emil rates Ian 5 (out of 5).Everyone else can have similar relationship properties.Cypher(Neo4j使用的类SQL语言)创建结点CREATE (ee:Person {name: 'Emil', from: 'Sweden', kloutScore: 99})返回结点MATCH (ee:Person) WHERE ee.name = 'Emil' RETURN ee;创建图谱MATCH (ee:Person) WHERE ee.name = 'Emil' CREATE (js:Person { name: 'Johan', from: 'Sweden', learn: 'surfing' }), (ir:Person { name: 'Ian', from: 'England', title: 'author' }), (rvb:Person { name: 'Rik', from: 'Belgium', pet: 'Orval' }), (ally:Person { name: 'Allison', from: 'California', hobby: 'surfing' }), (ee)-[:KNOWS {since: 2001}]->(js),(ee)-[:KNOWS {rating: 5}]->(ir), (js)-[:KNOWS]->(ir),(js)-[:KNOWS]->(rvb), (ir)-[:KNOWS]->(js),(ir)-[:KNOWS]->(ally), (rvb)-[:KNOWS]->(ally) 创建约束使得电影标签的所有节点的title保证唯一CREATE CONSTRAINT FOR (n:Movie) REQUIRE (n.title) IS UNIQUE CREATE CONSTRAINT FOR (d:Department) REQUIRE (d.title) IS UNIQUE表示为具有标签为"Movie"的所有节点的"released"属性创建索引。这意味着要为所有电影节点的发布日期属性创建一个索引，以提高对这个属性的查询性能。CREATE INDEX FOR (m:Movie) ON (m.released)
一些常用的windows操作小技巧一些题外话：（是否选择升级windows11）关于这个问题我觉得是因人而异，因为现在不也照样有人在使用win7.可能很多人觉得windows11有很多bug，所以继续选择win10.但这可能是一个伪命题，因为也许你可能根本遇不到这个问题比如你是学土木，而他是学计算机学计算机的可能在配置一些vscode等编译器时会遇到中文乱码问题，但这并不影响学土木的同学。作为一个快使用了一年半win11的人来说基本没有遇到什么问题，即使是像编译器乱码比如vscode其实也是可以通过配置setting.json文件来解决问题，至于使用idea这类IDE工具则完全无需担心这个问题，侧面也回答了win11能否作为生产力这个问题无论是剪辑视频用的达芬奇，pr,ae还是编程都不会遇到问题，对于开发者来说win11自带的wsl（windows下的linux子系统）也是学习linux的不二之选（较高版本的win10也有这个功能，使用前记得去控制面板中启用该功能），即使有也不会有网上视频说的那么不可接受，反正我用了win11以后是再也回不去了，过了一年win11的正式版不仅效率高，而且相较于win10颜值也高了不少，窗口过渡动画也变得更加丝滑.我最中意的功能------多窗口布局所以人生苦短，还有什么理由不升级win11呢？ps:当然对于一些早期的电脑性能有限的情况下，还是win10较为稳定快捷键篇我自己的键盘是将常用到控制按键键帽换成了蓝色一、win + shift + s相较于使用第三方截屏工具，windows自带的不仅功能强大而且自带，使用迅速二、shif + delete + enter快速删除文件，免去回收站再次删除，多文件删除时搭配ctrl + A就体现出了其优势，但是缺点就是无法撤回，所以使用之前还请慎重考虑三、win + D 搭配 ctrl + wwin + d可以让你快速返回上一个应用，也可以快速返回桌面，ctrl + w可以快速关闭当前窗口，这两个一搭配可以实现高效率摸鱼四、win11专属加减音量新姿势只需将鼠标移动至桌面右下角放在音量图标上，滚动滚轮即可实现音量加减（还不快去升级win11）五、程序员撸代码或文字处理小tips能量巨大但往往被忽视的控制区对于大多数编辑器文字的或代码的比如vscode, word, idea都支持home,end,ctrl按键的组合（啊，你说你用vim（全球最受程序员欢迎的编辑器）。哦那没事了确实熟练运用的话可以做到手不离键盘）比如Home/End跳转至该行代码的首或尾（对于word等非编程工具也同样适用）既然聪明如你那么应该清楚下面的快捷键进行的操作了ctrl + Home/ ctrl + End跳转到该文本的首或尾当然对于vscode来说你也可以通过ctrl + 鼠标点击代码块来进行跳转，而且对于vscode来说根本没必要记住快捷键因为你可以根据自己的习惯来进行任意修改软件推荐篇一、vscode----全球除了vim外最受程序员欢迎的编辑器对于开发人员来说，一款好的编辑器就是一件称手的兵器。传统的集成环境式编辑器不仅臃肿，而且占用大量资源，那么有没有一款编辑器既轻量，又功能强大呢？那么vscode将是你的不二之选，支持众多编程语言，可根据自己需求来添加扩展或功能，在进行一些轻量级开发时vscode将会是非常地nice.当然即使你完全不懂的编程也完全没有关系，你完全可以将vscode当成一个万能阅读器来处理文本信息（比如本篇文章就是用markdown + all in one插件来书写），vscode本质是一个编辑器所以不能直接上手写代码而需要手动配置文档，微软官方的doc文档写的非常详细，本人非常不建议阅读csdn或百度上什么博客上的教程配置，直接看官方不香吗？而且配置比如java或c/c++等语言环境也能让你学到不少东西二、powertoys----一款功能强大的小工具正所谓微软出品必属精品，既然是自家的操作系统那必然是如虎添翼，它含有窗口始终置顶功能这样你就不用担心点了一下另一个窗口而你当前的窗口被覆盖掉，它还有拾色器，和窗口布局等工具而其中我最喜爱的功能还得是鼠标实用工具当你因为思绪混乱而一时找不到鼠标时（双显示器应该会有这个烦恼），按两下ctrl键它就能让你礼貌而不失优雅地快速找到你的鼠标三、keyviz ---- 按键显示软件细心的小伙伴应该发现了在以上的gif中我输入的按键都会在屏幕的右下角显示，这款软件就是keyviz，在给他人分享屏幕或者录制教学视频时应该挺有帮助的他的动画和按键类型颜色大小出现时间，以及动画持续时间都可以自定义，而且非常地轻量仅有8m的大小还有免安装版本四、其他对于其他的我常用的软件就不单独分专栏来讲述了，而是笼统的在这里介绍bandzip 一款好用的解压缩软件，有充值版本但没必要免费就够用了potplayer 万能播放器，基于强大的ffmepg来编写基本上主流视频，音频格式都能播放，还可以外挂字幕有道云笔记 个人觉得最近比较好的云笔记，而且支持markdown格式书写xshell 开发人员必备连接远程服务器ssh工具git 每个开发人员都应该知道的版本管理软件，linus(linux之父)继linx之后又一名作（名场面）idea 由jetbrain公司开发，学生可以用学生证明免费白嫖ultrmate版本的最好用的java集成开发环境，打工人必备ScreenToGif 一款gif制作软件SAI2 一款画图软件有数位板的话可以拿来写笔记IDM 懂得都懂好的暂时分享到这，最近新加了一个基于gitalk的评论功能，如果各位小伙伴有什么好用的软件或工具也可以在评论区分享文章中有错误也可以指正,这里是黑夜梦想家，感谢您的阅读。
我的第一篇博客 “就同活着一样。并非因为有了结果，过程才具有意义。而是为了为了便宜地凸显过程这玩意的意义，抑或是拐弯抹角地比喻其局限性，才在某一个地点姑且设置一个结束。 ---《当我谈跑步时，我谈些什么》” [...]