普通视图

Received today — 2026年4月27日

浅谈前后端分离系统的SEO优化

作者obaby
2026年4月27日 10:03

开发一个系统,不管是从头开始,还是在已有系统上二次开发,从来都不是一蹴而就的事情。在上线以前总觉得已经做够了足够的测试,但是在上线之后还是会出现各种各样的问题。

有的问题,如果是新系统完全可以避免,正是由于是在已有系统上开发的为了兼容wp才会引入一系列的问题,这类问题主要是wp原生的一些机制兼容问题导致的包括但不限于:

1.wp固定连接的兼容

2.shortcode的解析处理

3.wp资源文件与新系统资源文件的路径兼容处理

4.wp启用插件的功能实现,邮件通知、micro-post、邮件发送、邮件模板等等

5.其他的未知问题

也有一部分是新系统天生的缺陷:seo不友好,搜索引擎爬虫无法获取网页内容,毕竟robot不会执行js,这个是前后端分离系统的必然缺陷。

<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <link
      rel="icon"
      href="https://zhongxiaojie.cn/wp-content/uploads/2026/01/uugai.com-166111691272754-100x100.png"
      sizes="32x32"
    />
    <link
      rel="icon"
      href="https://zhongxiaojie.cn/wp-content/uploads/2026/01/uugai.com-166111691272754-200x200.png"
      sizes="192x192"
    />
    <link
      rel="apple-touch-icon"
      href="https://zhongxiaojie.cn/wp-content/uploads/2026/01/uugai.com-166111691272754-200x200.png"
    />
    <meta
      name="msapplication-TileImage"
      content="https://zhongxiaojie.cn/wp-content/uploads/2026/01/uugai.com-166111691272754-300x300.png"
    />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta
      name="description"
      content="爱好广泛的女王 独立APP开发者 AI修理师 爬虫砖家 逆向工程师 人工智能 全栈工程师"
    />
    <meta
      name="keywords"
      content="人工智能,机器学习,ml,逆向分析,信息安全,物联网,ida,uniapp,python,爬虫,妹子图,秀人集,java,vue"
    />
    <meta
      name="theme-color"
      content="#ff4f87"
    />
    <link
      rel="manifest"
      href="/manifest.json"
    />
    <link
      rel="stylesheet"
      href="/vendor/enlighterjs.min.css"
    />
    <link
      rel="stylesheet"
      href="/vendor/simple-microblogging.css"
    />
    <title>obaby 𝐢‍𝐧⃝ void - 程序媛 / 独立开发者 / 智商不稳定的女神经</title>
    <script type="module" crossorigin src="/assets/index-DFHpxK1A.js"></script>
    <link rel="stylesheet" crossorigin href="/assets/index-CKljzL1r.css">
  </head>
  <body>
    <div id="app"></div>
    <script
      defer
      src="/vendor/enlighterjs.min.js"
    ></script>
    <script defer src="/vendor/obaby.js"></script>

  </body>
</html>

 

当然有人会比较在意这个东西,不是说这个东西不对。可能是自己没那么在乎吧,之前就曾经收到过数次关于seo友链不显示的问题,上次是搞页面静态化。

其实,在我的博客添加的友链,也并不是全部都不显示,毕竟还有其他的域名,zhongxiaojie.com 以及 oba.by等还是会显示完整的友链信息,这两个域名并没有切换到新的前后端分离的系统。所以,我博客的友链,相当于数个站都给友链做了多次链接,我不知道这个东西对于seo有没有作用,至于是有好处,还是有坏处,我并不清除,我自己并不是那么关注所谓的seo。如果觉得这样反而会出问题的,欢迎反馈,我会及时删除相关链接哈。

当然,这个东西有办法解决吗?答案自然是有,至于解决方法,那就是继续回归服务器渲染。

这解决方案真的是简单粗暴啊,合着这折腾来折腾去,又要弄回服务器渲染,这辛辛苦苦四十年,一夜回到解放前?

采用这种简单粗暴的方法来解决seo问题,显示不是本仙女的作风。既然是针对搜索引擎的,那就直接对搜索引擎做单独的处理就完了。检测ua,如果是收缩引起的ua返回服务器渲染之后的内容,如果是正常浏览(搜索引擎爬虫意外的ua)返回前后端分离的内容。

要实现服务器渲染,基于vue的可以参考nuxt.js(百度百科):

Nuxt.js是由NuxtLabs团队于2016年10月推出的基于Vue.js的开源Web框架,采用MIT License授权。该框架灵感来源于Next.js,Nuxt采用了约定俗成的规范以及一种明确的目录结构,以实现对重复性任务的自动化处理,并使开发人员能够专注于推进新功能的开发。 [2] [5] [8]
Nuxt默认内置服务器端渲染(SSR)功能、支持静态站点生成(SSG)和单页面应用(SPA)三种部署模式,可通过”nuxt generate”命令生成预渲染HTML文件实现静态化部署 [5] [7]。采用模块化架构提供50多个扩展模块,支持TypeScript类型安全、推送和现代化开发工具链 [4] [6]

接下来也就简单了,创建nuxt项目,实现与frontend同样的页面路由和相关的页面文件布局。接口可以直接复用当前的接口,

配置openresty的处理逻辑:

# -----------------------------------------------------------------------------
# Dynamic Rendering(SEO):爬虫 UA → Nuxt SSR;普通用户 → 现有 SPA
# - Nuxt SSR 服务建议监听 127.0.0.1:3000(可按需调整)
# - ?__ssr=1 可强制走 SSR(方便自测/排障)
# - 仅对“页面路由”生效,不影响 /assets、/vendor、/bp-api、WP 后台等
# -----------------------------------------------------------------------------
set $bp_force_ssr 0;
if ($arg___ssr = "1") {
    set $bp_force_ssr 1;
}

set $bp_is_bot 0;
if ($http_user_agent ~* "(googlebot|bingbot|baiduspider|yandexbot|duckduckbot|slurp|sogou|360spider|bytespider|petalbot|facebookexternalhit|twitterbot|rogerbot|ahrefsbot|semrushbot|mj12bot)") {
    set $bp_is_bot 1;
}

location @nuxt_ssr {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    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;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Uri $request_uri;
}

# 418 跳转技巧:在页面路由里 return 418 → error_page 转到 @nuxt_ssr
error_page 418 = @nuxt_ssr;

启动之后就可以查看服务器渲染的页面了:

当然,这个实现方法的缺点就是得完全复刻frontend的相关路由和页面,优点就是不用关注原来的系统实现逻辑,哪怕爬虫seo系统出问题也不会影响现有的系统运行。

 

Received before yesterday

U-Boot、内核移植与根文件系统构建(BeagleBone Green Gateway&amp;AM335X)

作者Echo
2026年4月25日 22:36

前言

本文档主要记录了基于 BeagleBone Green Gateway 开发板(核心芯片为 TI AM3358)的 U-Boot、内核移植与根文件系统构建全流程。内容涵盖了在 Ubuntu 下搭建交叉编译环境、编译 Linux 4.19 内核U-Boot、设备树 的详细步骤,在移植过程中遇到的编译器兼容性问题(如 GCC 10+ 报错、架构检测失效)及其修复方法。

一:安装交叉编译工具链

关于 安装 ARM 交叉编译工具链 的教程笔记。

  • 宿主机 (Host): 你的电脑 (Ubuntu x86_64)。
  • 目标机 (Target): 开发板 (AM335x ARMv7)。
  • 交叉编译器: 在 x86 上运行,但生成的是能在 ARM 上运行的可执行代码。

方法 A:使用 APT 包管理器 (最简单,推荐)

这是最快的方法,直接从 Ubuntu 软件源安装。

1. 更新源

sudo apt-get update

2. 安装基础构建工具 (Host 工具)
编译内核不仅需要交叉编译器,还需要主机端的 gcc、make、bison 等工具。

sudo apt-get install build-essential bison flex libssl-dev lzop u-boot-tools device-tree-compiler

3. 安装交叉编译器
安装 Hard Float (hf) 版本的编译器,适配 AM335x 的硬件浮点单元。

# gcc (C编译器) 和 g++ (C++编译器)
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf

方法 B:手动安装 Linaro 版本 (指定版本,进阶)

如果你需要特定版本的 GCC (例如为了避开 GCC 10+ 的语法检查严格问题,或者为了匹配旧内核),可以使用此方法。

1. 下载编译器包
前往 Linaro 官网下载 (例如 GCC 7.5):

  • 文件名示例:gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

2. 创建目录并解压
通常安装在 /usr/local/arm 目录下。

sudo mkdir -p /usr/local/arm
# 假设压缩包在当前目录
sudo tar -vxf gcc-linaro-7.5.0-*.tar.xz -C /usr/local/arm/

3. 配置环境变量 (PATH)
为了让终端能在任何地方找到这个命令,需要修改 ~/.bashrc

vim ~/.bashrc

在文件最末尾添加:

# 注意将下面的路径换成你实际解压后的文件夹名
export PATH=$PATH:/usr/local/arm/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin

4. 生效配置

source ~/.bashrc

验证安装

无论用哪种方法,安装完成后必须验证。

1. 检查版本

arm-linux-gnueabihf-gcc -v

2. 预期输出

  • 最后一行应显示 gcc version x.x.x ...
  • 如果提示 command not found,说明没安装好或者环境变量没配对。

后缀的区别 (坑点预警)

在下载或安装时,你会看到不同的后缀,千万别选错

后缀名全称含义适用场景
gnueabihfHard Float使用硬件 FPU (浮点单元) 进行运算AM335x (你的板子), Raspberry Pi 等现代 ARM
gnueabiSoft Float使用软件模拟浮点运算 (速度慢)非常古老的 ARM9 或无 FPU 的芯片
aarch64ARM6464位 ARM 架构树莓派4 (64位系统), 手机芯片, RK3399

常用命令别名

为了避免每次编译都要输那一长串前缀,可以在 ~/.bashrc 里加个变量:

# 在 ~/.bashrc 末尾添加
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm

这样以后编译内核只需输:

make zImage  # 甚至不用输 ARCH 和 CROSS_COMPILE,只要 Makefile 支持读取环境变量

二: U-Boot编译和移植

目标:制作一张能引导开发板启动的 SD 卡。

编译 U-Boot

  • 作用:初始化硬件(CPU, DDR),为加载内核做准备。
  • 命令
# 获取
git clone https://github.com/beagleboard/u-boot.git
cd u-boot
git checkout v2021.10-bbb.io-am335x # 切换到对应分支

cd /home/dq/linux/uboot/beagleboard-u-boot

# 清理旧编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
# 配置 (AM335x 通用配置)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- am335x_evm_defconfig
# 编译 (-j4 使用4核加速)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4

产物MLO (一级引导), u-boot.img (二级引导)。

  • ROM Code(芯片出厂自带):寻找 MLO 并加载到 SRAM。
  • MLO:初始化 DDR3,寻找 u-boot.img 并搬运到 DDR3。
  • u-boot.img:运行命令行,加载 Kernel(Linux 内核)。
  • Kernel:挂载 Rootfs(根文件系统),启动用户空间。

SD 卡分区与烧录

  • 作用:将 SD 卡分为 Boot 分区 (FAT32) 和 Rootfs 分区 (EXT4)。
  • 命令

sd卡格式化脚本

#! /bin/sh
# mkcard.sh v0.5
# (c) Copyright 2009 Graeme Gregory <dp@xora.org.uk>
# Licensed under terms of GPLv2
#
# Parts of the procudure base on the work of Denys Dmytriyenko
# http://wiki.omap.com/index.php/MMC_Boot_Format

export LC_ALL=C

if [ -z `which bc` ]; then
    echo "no bc binary found"
    exit 1;
fi

if [ $# -ne 1 ]; then
    echo "Usage: $0 <drive>"
    exit 1;
fi

DRIVE=$1

# 清除 SD 卡头部信息
dd if=/dev/zero of=$DRIVE bs=1024 count=1024

# 获取磁盘大小
SIZE=`fdisk -l $DRIVE | grep Disk | grep bytes | awk '{print $5}'`

echo DISK SIZE - $SIZE bytes

# 计算柱面
CYLINDERS=`echo $SIZE/255/63/512 | bc`

echo CYLINDERS - $CYLINDERS

# 使用 sfdisk 进行分区
# 分区1: 63MiB, 类型 0x0C (FAT32 LBA), 可启动 (*)
# 分区2: 4GiB (或剩余空间), 类型默认 (Linux)
sudo sfdisk $DRIVE << EOF
8192,63MiB,0x0C,*
137216,4GiB,,-
EOF

sleep 1

# 格式化分区 1 为 FAT32 (boot)
if [ -b ${DRIVE}1 ]; then
    umount ${DRIVE}1
    mkfs.vfat -F 32 -n "boot" ${DRIVE}1
else
    if [ -b ${DRIVE}p1 ]; then
        umount ${DRIVE}p1
        mkfs.vfat -F 32 -n "boot" ${DRIVE}p1
    else
        echo "Cant find boot partition in /dev"
    fi
fi

# 格式化分区 2 为 ext4 (rootfs)
if [ -b ${DRIVE}2 ]; then
    umount ${DRIVE}2
    mkfs.ext4 -L "rootfs" ${DRIVE}2
else
    if [ -b ${DRIVE}p2 ]; then
        umount ${DRIVE}p2
        mkfs.ext4 -j -L "rootfs" ${DRIVE}p2
    else
        echo "Cant find rootfs partition in /dev"
    fi
fi
cd /home/dq/linux/tool
# 运行脚本格式化 sdb (注意:你的设备号是 sdb)
sudo ./mkcard.sh /dev/sdb

# 挂载并拷贝引导文件
sudo mount /dev/sdb1 /mnt/boot  # (或依赖自动挂载 /media/dq/boot)
sudo cp ../../linux/uboot/beagleboard-u-boot/MLO /mnt/boot/
sudo cp ../../linux/uboot/beagleboard-u-boot/u-boot.img /mnt/boot/

三:Linux 内核编译与部署

目标:编译内核,并解决 U-Boot 网卡驱动不兼容的问题(采用“SD卡存内核 + NFS存文件系统”的混合策略)。

编译内核与设备树

  • 作用:编译操作系统核心 (zImage) 和硬件描述文件 (.dtb)。
  • 命令
# 获取
git clone https://github.com/beagleboard/linux.git --depth 1 -b 4.19.94-ti-r42

cd /home/dq/linux/tool/linux-4.19.94-ti-r42/
# 配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bb.org_defconfig
# 编译内核、设备树和模块
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage dtbs modules -j4

生成三个部分

  • zImage: 内核镜像。位于 arch/arm/boot/zImage
  • dtbs: 设备树二进制文件。位于 arch/arm/boot/dts/am335x-bonegreen-gateway.dtb
  • modules: 驱动模块。它们被编译成了分布在各个目录下的 .ko 文件。

TFTP 配置

目的:uboot启动后通过tftp拉取镜像zimag和设备树dtb

  • 无需手动拷贝:Ubuntu 编译生成的产物直接放在 TFTP 根目录,开发板重启时自动从网络拉取。
  • 保护 SD 卡:减少对物理存储介质的读写,避免频繁挂载导致的 FAT 分区损坏。
  • 纯内存运行:内核和设备树直接加载到 RAM,不占用 SD 卡空间。

Ubuntu 配置 TFTP

1. 安装服务程序

使用最稳健的 tftpd-hpa 包:

sudo apt-get update
sudo apt-get install tftpd-hpa tftp-hpa

2. 创建工作目录并赋权 (关键)

默认路径通常在 /var/lib/tftpboot,但为了开发方便,建议修改到用户目录下,并赋予最高权限防止“Permission denied”。

# 1. 创建目录 (建议放在你的工作区)
mkdir -p /home/dq/linux/tftpboot

# 2. 赋予最高权限 (允许任意读写,开发环境图方便)
chmod 777 /home/dq/linux/tftpboot

3. 修改配置文件

编辑 /etc/default/tftpd-hpa,将默认配置修改为指向你的新目录。

sudo vim /etc/default/tftpd-hpa

修改后的完整内容:

# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
# 修改 1: 指向你刚才创建的目录
TFTP_DIRECTORY="/home/dq/linux/tftpboot" 
TFTP_ADDRESS=":69"
# 修改 2: 增加 --create 允许上传(可选),保持 --secure
TFTP_OPTIONS="--secure --create"

4. 重启服务并生效

每次修改配置文件后,必须重启服务:

sudo service tftpd-hpa restart

5. 避坑指南:防火墙 (必做)

TFTP 使用 UDP 69 端口,极易被 Ubuntu 防火墙拦截。开发阶段建议直接关闭,或者放行端口。

# 方案 A: 简单粗暴关闭防火墙 (推荐)
sudo ufw disable

# 方案 B: 仅放行 UDP 69
sudo ufw allow 69/udp

6. 本地自测 (验证服务是否存活)

在烧录板子前,先自己连自己测试一下,确保不是 Ubuntu 内部的问题。

# 在 tftpboot 目录下创建一个测试文件
touch /home/dq/linux/tftpboot/test.txt

# 回到家目录尝试下载
cd ~
tftp 127.0.0.1
tftp> get test.txt
tftp> q

# 检查是否下载成功
ls test.txt

如果 ls 能看到文件,说明服务端配置完美!


备选方案 (SD卡部署)

  • 现状:你的 U-Boot 探测不到 PHY 地址 1,网络链路(Link Up)无法建立。
  • 代价:每次修改内核或设备树,必须先进入 Linux,手动挂载 /dev/mmcblk0p1/mnt/sd_boot,然后 cp 覆盖,效率较低
  • 原因:U-Boot 无法通过 TFTP 联网下载,所以直接把内核拷进 SD 卡让它读取。
  • 命令
# 假设 SD 卡 boot 分区挂载在 /media/dq/boot
sudo cp arch/arm/boot/zImage /media/dq/boot/
sudo cp arch/arm/boot/dts/am335x-bonegreen-gateway.dtb /media/dq/boot/
sync  # 同步数据,防止丢失

PS: 后面替换设备树和系统镜像可以通过将sd卡挂载到开发板,然后通过nfs共享文件,将其拷贝到sd卡boot分区


开发板配置

设置产物自动归档
在编译脚本末尾或手动执行,将产物推送到 TFTP 目录(假设为 /home/dq/tftpboot):

cp arch/arm/boot/zImage /home/dq/tftpboot/
cp arch/arm/boot/dts/am335x-bonegreen-gateway.dtb /home/dq/tftpboot/

U-Boot 配置指令 (开发板端)

在 U-Boot 命令行设置网络参数及自动化命令:

  1. 设置网络 IP
setenv ipaddr 192.168.10.13       # 开发板 IP
setenv serverip 192.168.10.200    # Ubuntu 服务器 IP
saveenv
  1. 定义自动化启动脚本 (bootcmd)
# 逻辑:从网络下载 dtb 到 0x88000000 -> 下载 zImage 到 0x82000000 -> 启动内核
setenv loadtftp 'tftp 88000000 am335x-bonegreen-gateway.dtb; tftp 82000000 zImage'
setenv bootcmd 'run loadtftp; bootz 82000000 - 88000000'
saveenv
  1. 正常工作时的现象

当一切配置正确且 PHY 地址匹配时,U-Boot 启动会显示:

link up on port 0, speed 100, full duplex
Using ethernet@4a100000 device
TFTP from server 192.168.10.200; our IP address is 192.168.10.13
Filename 'am335x-bonegreen-gateway.dtb'.
Load address: 0x88000000
Loading: ############  (此处会出现大量井号,表示数据高速传输)
done
Bytes transferred = 56234 (dbaa hex)

四:根文件系统构建以及NFS配置

目标:在 Ubuntu 上建立一个文件夹,让开发板通过网线把它当成“硬盘”来挂载,实现文件实时同步,同时加载根文件系统。

# 根文件系统下载
wget -c https://rcn-ee.com/rootfs/eewiki/minfs/debian-10.3-minimal-armel-2020-02-10.tar.xz

安装模块到根文件系统

❯ pwd
/home/dq/linux/nfs/rootfs/lib/modules/4.19.94

# 生成配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bb.org_defconfig

# 编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules -j4

# 安装
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/home/dq/linux/nfs/rootfs/ modules_install

Ubuntu服务端配置

  1. 安装 NFS 服务
sudo apt-get update
sudo apt-get install nfs-kernel-server
  1. 创建并准备根文件系统目录

假设你的根文件系统(Rootfs)存放在 /home/dq/linux/nfs/rootfs

PS: 不同根文件压缩包格式需要不同方式解压

# 1. 创建目录
mkdir -p /home/dq/linux/nfs/rootfs

# 2. 假设你在压缩包所在目录
# -x: 解压, -v: 显示进度, -J: 处理 xz 格式, -f: 指定文件
sudo tar -xvJf debian-10.3-minimal-armel-2020-02-10.tar.xz -C /home/dq/linux/nfs/rootfs/
  1. 配置共享权限 (exports)

NFS 的权限控制通过 /etc/exports 文件管理。

sudo vim /etc/exports

在文件末尾添加以下一行:

/home/dq/linux/nfs/rootfs *(rw,sync,no_root_squash,no_subtree_check)
  • 参数解析
  • rw:可读可写。
  • sync:同步写入(保证数据一致性)。
  • no_root_squash最关键参数。允许板子的 root 用户拥有 Ubuntu 侧对应的 root 权限。如果不加这个,板子无法以 root 身份运行,会导致权限报错。
  • no_subtree_check:禁用子树检查,提高稳定性。
  1. 重启并生效服务
# 重新扫描 exports 文件并使配置生效
sudo exportfs -arv

# 重启 NFS 服务
sudo service nfs-kernel-server restart
  1. 避坑指南:网络与防火墙

NFS 依赖多个端口(RPC),如果防火墙开启,挂载必然失败。

# 直接关闭防火墙(开发环境推荐)
sudo ufw disable

U-Boot设置

直接看第五阶段

五:U-Boot 启动配置

目标:设置 U-Boot 环境变量,启动系统。

TFTP可以使用

即第二阶段tftp开发板的配置

setenv ipaddr 192.168.10.13       # 开发板 IP
setenv serverip 192.168.10.200    # Ubuntu 服务器 IP
saveenv

# 逻辑:从网络下载 dtb 到 0x88000000 -> 下载 zImage 到 0x82000000 -> 启动内核
setenv loadtftp 'tftp 88000000 am335x-bonegreen-gateway.dtb; tftp 82000000 zImage'
setenv bootcmd 'run loadtftp; bootz 82000000 - 88000000'
saveenv

# 设置 NFS 挂载参数 (注意 IP 地址)
setenv bootargs 'console=ttyS0,115200n8 root=/dev/nfs nfsroot=192.168.10.200:/home/dq/linux/nfs/rootfs,v3,tcp ip=192.168.10.13:192.168.10.200:192.168.10.100:255.255.255.0::eth0:off'

# 启动
boot

TFTP无法使用

  • 作用:告诉板子“从 SD 卡读内核,去 192.168.10.200 挂载 NFS”。
  • 命令 (在串口终端执行):
# 1. 从 SD 卡读取内核和 DTB
setenv bootcmd 'load mmc 0:1 0x82000000 zImage; load mmc 0:1 0x88000000 am335x-bonegreen-gateway.dtb; bootz 0x82000000 - 0x88000000'

# 2. 设置 NFS 挂载参数 (注意 IP 地址)
setenv bootargs 'console=ttyS0,115200n8 root=/dev/nfs nfsroot=192.168.10.200:/home/dq/linux/nfs/rootfs,v3,tcp ip=192.168.10.13:192.168.10.200:192.168.10.100:255.255.255.0::eth0:off'

# 启动
boot

六:Hello World

目标:验证开发板镜像是否正常工作。

  1. 编写与静态编译
  2. 问题:动态编译报错 No such file (缺少动态库)。
  3. 解决:使用 -static 静态链接。
  4. 命令 (在 Ubuntu 端):
#include <stdio.h>

int main() {
    printf("--------------------------------------\n");
    printf("  Hello, BBGG! This is Gemini speaking. \n");
    printf("  NFS cross-compile works perfectly!   \n");
    printf("--------------------------------------\n");
    return 0;
}
cd /home/dq/linux/nfs/rootfs/home/debian
# 编写代码
sudo vim hello.c 

# 交叉编译 (静态链接)
sudo arm-linux-gnueabihf-gcc -static hello.c -o hello
  1. 板上运行
  2. 命令 (在串口终端):
cd /home/debian
./hello
  • 结果:成功输出 Hello, BBGG!...

补充

在嵌入式 Linux 开发中,解决 GCC 版本冲突(重定义错误)架构检测失败(ISB 指令错误) 是适配旧内核(如 4.19)的关键步骤。以下是针对这两处修改的笔记整理:


1. 解决主机工具编译冲突 (yylloc 多重定义)

背景:当 Ubuntu 宿主机的 GCC 版本 10 时,默认开启 -fno-common,导致内核自带的 dtc(设备树编译器)工具在链接时报错。

  • 修改文件:顶层 Makefile
  • 具体位置:搜索 KBUILD_HOSTCFLAGS 定义处(通常在 400 行左右)。
  • 修改内容
    在变量末尾手动添加 -fcommon 参数。
# 原代码:
KBUILD_HOSTCFLAGS   := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 \
                       -fomit-frame-pointer -std=gnu89 $(HOST_LFS_CFLAGS) \
                       $(HOSTCFLAGS)

# 修改后:
KBUILD_HOSTCFLAGS   := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 \
                       -fomit-frame-pointer -std=gnu89 -fcommon $(HOST_LFS_CFLAGS) \
                       $(HOSTCFLAGS)

2. 解决架构降级导致的汇编错误 (isb 指令不支持)

背景:内核通过 cc-option 测试编译器。在使用硬浮点(Hard-Float)交叉编译器时,由于测试命令缺少 FPU 参数导致测试失败,内核 Makefile 会误认为编译器不支持 ARMv7,从而自动降级到 ARMv5,导致不识别 v7 指令 isb

  • 修改文件arch/arm/Makefile
  • 具体位置:搜索 CONFIG_CPU_32v7 所在行(通常在 65 行左右)。
  • 修改内容
    废除自动检测逻辑,直接硬编码(Hardcode)指定架构为 -march=armv7-a
# 原代码:
arch-$(CONFIG_CPU_32v7)  := -D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)

# 修改后(删除检测函数,直接指定架构):
arch-$(CONFIG_CPU_32v7)  := -D__LINUX_ARM_ARCH__=7 -march=armv7-a

难熬的工作日常,风雨之后有彩虹吗

作者Hary
2026年4月25日 21:55

 最近两周实在是过得煎熬,月初假期之后连续几天阴雨连绵,9号上午,我的同事S突然给我发个消息说,我接下来可能要更忙了,然后就发过来几张在医院的检查单,说是由于下雨,在楼梯上摔倒了,导致脚踝两侧两处骨折。
 唉,真是想不到的事,不知道具体怎么摔的,也没好多问,直接摔两处骨折,还是有点严重的,上周几天就各种检查,后来说是要手术,上周二的时候安排了手术,然后观察了几天,上周末让回家修养了,出院之后还要再修养至少一个月。
 这一受伤不当紧,原本我俩干的事情,现在全都压到我头上来了,四五个项目同时进行,实在是有点焦头烂额,上周领导给我安排了个小弟,结果过来只会搞一些简单的文档类工作,我给他整好模板,copy但是能搞,但是这样好像并不会给我分担多少工作量啊,这几周固定都是每周两个操作,也就是要白天要沟通进展,准备方案,晚上要加班操作的话就要凌晨搞到四五点,实在是难顶。
 昨天快下班的时候领导H给我打电话说,下周要安排地市的另外一个兄弟过来支撑一个月,说是我们另外一个领导W跟他讲的我这边事情太多了,让安排一个人过来分担操作,还说我实在忙不过来要跟他讲。我心想,不是当时我跟你讲的时候了,我说我同事S要请假的话我这边一个人忙不过来,结果给我安排一个小白,我当时都讲了,不能分担操作,过来也没啥作用啊,到时候五月份我一周安排三个操作我自己也干不了啊,当时H还跟我讲,先干着,看让他搞一些简单的,现在又问我忙不过来怎么不跟他讲了。。。
 现在整得各地市各专业都人员紧张的一批,降岗降薪,另外还辞退几个,我宿舍这个室友之前通知的让干到三月底,然后四月初开始就和公司谈赔偿问题,来来回回四五个回合也没谈拢,我这个室友说是在这边七年多快八年了,想谈个N+1,公司本来只同意赔偿不到二分之一N,应该是上上周吧,我这个室友往公司寄了个起诉告知函,准备拿起法律武器搏一搏,结果上周末公司领导过来就找他一起又谈了一波,最后双方都让步了一点,说是赔了个½N多点,但是不到N,也算是解决了。
 然后我这个同事最近都在各种投简历面试,准备去往杭州,上海那边找个销售类岗位,一直也没啥进展,确实这年头合适的工作不好找。
 所以即使还在坑位里的牛马已经被压迫的这么狠了,估计也还狠不下心来离职吧,狠不下心来那还是没压迫到位,唉,走一步看一步吧,真到哪天离职了也未尝不是个机会。

产品,还是玩具? — Baby Press(缝合怪)

作者obaby
2026年4月24日 14:58

这算是给这个东西写的第二篇正式的文章,本来我的想法很简单,做一个简单的前后端分离的系统来完全替代wp的php渲染机制。

只是,在开发的过程中为了迎合wp的各种现有数据格式、插件、主题、shortcode等等,代码复杂度也在不断的提高。得益于ai的崛起,现在生成代码是真的简单方便,原来数个人的工作,现在一人就可以完成了。尽管哪怕没有ai,我自己也能全部搞定。ai在某些方便还是提高了输出效率,原本很多人不是全栈的,现在也给搞成了全干工程师,哪怕不会,也得硬着头皮上,去验证ai写的各种代码。

我一般不喜欢给ai太具体的描述,但是会给一个准确的描述,实现方法,实现路径,实现目标,所以多数时候ai呈现的代码质量尚可。然而,等到实际上线的时候发现还是一堆问题。

做完准备把wp的前端全部迁移到现在的baby press的前端,尝试部署之后出现了一系列问题,当然很多问题源自于测试不充分。为了解决两个系统的整合问题,需要大量的配置文件和代码。除了openresty的配置文件,前后端也生成了一堆默认的配置模板,当然,这些模板主要是为了提供一些自定义的功能,以及安全性提升加密等等。

这么复杂的系统,现在我觉得更像一个玩具,而不是产品,好的产品应该是简单易用,开箱可用的。

DJANGO_SECRET_KEY=dev-secret-key-change-me
DJANGO_DEBUG=1
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost
# 浏览器里「页面」的 origin(协议+域名+端口),须与前端访问地址一致;逗号分隔、勿加路径。
# 生产示例(Vue 部署在 i 子域、API 在 api 子域时,必须把 i 子域写进来,否则会 CORS 失败):
# CORS_ALLOWED_ORIGINS=http://127.0.0.1:5173,http://localhost:5173,http://i.zhongxiaojie.cn,https://i.zhongxiaojie.cn
CORS_ALLOWED_ORIGINS=http://127.0.0.1:5173,http://localhost:5173
# Django CSRF 信任来源(协议+域名+端口,逗号分隔;用于 /admin/login/ 等表单提交)
# 生产示例:CSRF_TRUSTED_ORIGINS=https://api.zhongxiaojie.cn,https://i.zhongxiaojie.cn
CSRF_TRUSTED_ORIGINS=http://127.0.0.1,http://localhost

# Django 缓存(评论 UA/IP 查询结果);推荐 Redis,例如 redis://127.0.0.1:6379/1
# 留空则使用 LocMem(仅开发、单进程)
# DJANGO_CACHE_REDIS_URL=redis://127.0.0.1:6379/1
#
# WordPress Object Cache Pro(可选):Django 直写评论后用于定向清理评论缓存。
# 请与 WordPress 端 WP_REDIS_CONFIG 的 host/db/prefix 保持一致。
# 例如 WP_REDIS_CONFIG 里 database=5,则这里应为 redis://127.0.0.1:6379/5
# WP_OBJECT_CACHE_REDIS_URL=redis://127.0.0.1:6379/<database>
# 注意:当前定向清理实现依赖 prefix,建议在 WP_REDIS_CONFIG 中显式配置 'prefix' => 'zhxj'
# WP_OBJECT_CACHE_REDIS_PREFIX=zhxj
# WP_OBJECT_CACHE_BLOG_ID=0

# Baby IP Lookup:本机 lookup-ua 与静态资源公网域名(PNG/SVG 补全)
# UA_LOOKUP_UPSTREAM_BASE_URL=http://127.0.0.1:18765
# UA_LOOKUP_PUBLIC_ASSETS_BASE_URL=https://ip.zhongxiaojie.cn
# UA_LOOKUP_DEFAULT_METHOD=ip2location
# UA_LOOKUP_CACHE_TTL=604800

# WordPress database connection (MySQL/MariaDB)
WP_DB_NAME=wordpress
WP_DB_USER=root
WP_DB_PASSWORD=
WP_DB_HOST=127.0.0.1
WP_DB_PORT=3306

# WordPress table prefix, e.g. wp_ / wp123_
WP_TABLE_PREFIX=wp_

# 是否信任反代/CDN 转发头(CF-Connecting-IP / X-Real-IP / X-Forwarded-For),默认开启。
# - 生产推荐开启,并配置 TRUSTED_PROXY_IP_RANGES,只信任你的网关/CDN 回源 IP 段
# - 若 API 不会被公网直连,且 CDN 回源 IP 经常变:可保持开启并留空 TRUSTED_PROXY_IP_RANGES(有伪造风险)
TRUST_PROXY_HEADERS=1
# 反代终止 TLS(如 Nginx/Edge/CDN)时建议开启,配合 X-Forwarded-Proto 识别 https
SECURE_PROXY_SSL_HEADER_ENABLED=1

# 额外输出“真实 IP access log”(Daphne 的 access log 里显示的是 CDN 节点 IP)
# 打开后会在 stdout 输出形如:[realip] ip=... remote=... status=... GET /api/...
REAL_IP_ACCESS_LOG_ENABLED=0

# 受信任反向代理 / CDN 的 IP 段(CIDR,逗号分隔)。
# 仅当请求来源 REMOTE_ADDR 命中这些 IP 段时,后端才会信任 CF-Connecting-IP / X-Real-IP / X-Forwarded-For。
# - 本机 Nginx 反代:127.0.0.1/32,::1/128
# - 生产:把你的 Nginx/网关内网地址段、或 CDN 回源 IP 段加入这里
TRUSTED_PROXY_IP_RANGES=127.0.0.1/32,::1/128

# API 请求签名(HMAC + ts + nonce)——默认关闭
# 注意:这是“请求验签”,不是“返回加密”。建议仅在 HTTPS 下启用。
# API_SIGNING_ENABLED=1
# API_SIGNING_SECRET=change-me-long-random
# 允许客户端时间漂移(秒),超出即拒绝(防离线重放)
# API_SIGNING_TTL_SECONDS=60
# nonce 去重缓存 TTL(秒),建议 >= API_SIGNING_TTL_SECONDS
# API_SIGNING_NONCE_TTL_SECONDS=300
# 需要签名的路径前缀(逗号分隔)
# API_SIGNING_REQUIRED_PREFIXES=/api/
# 免签路径(逗号分隔,严格 path 匹配),例如健康检查:
# API_SIGNING_EXEMPT_PATHS=/api/health/,/api/ping/

# SMTP / Email backend (Django)
# 不配置则不会真的发出邮件(除非你使用本地控制台邮件后端等)。
# EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
# EMAIL_HOST=smtp.example.com
# EMAIL_PORT=587
# EMAIL_USE_TLS=1
# EMAIL_HOST_USER=your-account@example.com
# EMAIL_HOST_PASSWORD=your-app-password
# DEFAULT_FROM_EMAIL="obaby <no-reply@zhongxiaojie.cn>"
#
# 评论回复邮件通知(前台回复他人评论时)
# COMMENT_REPLY_NOTIFICATION_ENABLED=1
# COMMENT_REPLY_EMAIL_FROM="obaby <no-reply@zhongxiaojie.cn>"
# COMMENT_REPLY_EMAIL_HEADER_IMAGE_URL=https://zhongxiaojie.com/wp-content/uploads/2026/01/uugai.com_1661691241113463.png
# COMMENT_REPLY_EMAIL_HEADER_IMAGE_WIDTH=520
# COMMENT_REPLY_EMAIL_HEADER_IMAGE_HEIGHT=180
# COMMENT_REPLY_EMAIL_HEADER_ALT=obaby 𝐢‍𝐧⃝ void
# COMMENT_REPLY_EMAIL_FOOTER_LINE1=obaby 𝐢‍𝐧⃝ void
# COMMENT_REPLY_EMAIL_FOOTER_LINK_TEXT=oba.by
#
# 与 WordPress CREN 插件退订链接校验一致(取自 wp-config.php)
# WORDPRESS_AUTH_KEY=
# WORDPRESS_AUTH_SALT=
# 与 WordPress 登录 Cookie(wordpress_logged_in_*)校验一致(同样取自 wp-config.php)
# 推荐配置 LOGGED_IN_KEY / LOGGED_IN_SALT;留空时后端会回退到 AUTH_KEY / AUTH_SALT
# WORDPRESS_LOGGED_IN_KEY=
# WORDPRESS_LOGGED_IN_SALT=

# 服务器状态小组件:统计磁盘路径(Linux "/";Windows "C:\\")
# SERVER_PROBE_DISK_PATH=/

# 
列表头像:Gravatar 兼容镜像根(路径同 /avatar/{md5}?s=&d=),默认 gg.lang.bi # GRAVATAR_AVATAR_BASE_URL=https://gg.lang.bi # 侧边栏「近期文章」:正文无图时的缩略图回退地址 # SIDEBAR_RECENT_POST_FALLBACK_IMAGE_URL=https://zhongxiaojie.cn/wp-content/uploads/2026/01/... # 评论反垃圾分类(可选;不配置则不调服务、新评论直接通过) # BABY_ANTI_SPAM_CLASSIFY_URL=http://192.168.1.8:8765/v1/classify # BABY_ANTI_SPAM_SECRET=change-me-long-random # BABY_ANTI_SPAM_TIMEOUT=3 # 同一邮箱+IP 对同一篇文章连续提交的最短间隔(秒,0 关闭,最大 120);依赖 Django cache # COMMENT_SUBMIT_COOLDOWN_SECONDS=0 # 前台文章评论列表分页(GET /api/wp/posts/:id/comments/):按一级评论(线程)分页,每页含该层全部回复;不传 page 时默认最后一页(最新线程) # WP_COMMENTS_PER_PAGE=50 # 客户端 ?per_page= 的上限(不超过 500) # WP_COMMENTS_MAX_PER_PAGE=200 # 顶层线程展示:desc=递减(最新在上,默认);asc=递增(最新在下) # WP_COMMENTS_ORDER=desc # Nginx FastCGI 缓存:评论审核通过(comment_approved=1)后清理文章页、首页(可选分类页) # 与 WordPress 插件「Nginx FastCGI Cache Purge on Comment」类似:HTTP GET {站点}/purge{路径} # NGINX_CACHE_PURGE_ENABLED=1 # NGINX_PURGE_PUBLIC_BASE_URL=https://你的域名 # NGINX_PURGE_TIMEOUT=2 # NGINX_PURGE_SSL_VERIFY=1 # NGINX_PURGE_CATEGORIES=1 # NGINX_CACHE_FILES_PATH=/var/cache/nginx/allinone # Kama WP Smile:评论表情包资源(给前端下发,避免硬编码域名) # 若留空,前端会回退使用自身默认/环境变量配置。 # SMILE_PACK_BASE_URL=https://zhongxiaojie.cn/wp-content/plugins/kama-wp-smile-packs/qip_dark_all/ # SMILE_PACK_EXT=gif # SMILE_PACK_TOKENS=smile,sad,laugh,rofl,blum,kiss,yes,no,good,bad,unknw,sorry,pardon,wacko,acute,boast,boredom,dash,search,crazy,yess,cool,air_kiss,angel,bb,beach,aggressive,blush,bomb,bravo,buba,bye,cry,curtsey,dance,dash2,declare,diablo,don-t_mention,drinks,focus,fool,friends,gamer,give_rose,heart,help,hi,laugh1,mail,mda,mosking,music,negative,ok,popcorm,punish,rtfm,sarcastic,secret,shock,shout,thank_you,vava,victory,beee,big_boss,wink,yu,cray2,dash3,girl_pinkglassesf,girl_prepare_fish,locomotive,lazy2,agree,feminist,fuk,fuck,jester,hunter,moil,offtopic,paladin,shablon_01,spam,vinsent,warning,yahoo,superman,girl_witch,fans,beta,butcher,elf,first_move,gamer2,girl_cray2,girl_cray,girl_blum,girl_dance,girl_crazy,girl_haha,heat,hysteric,nhl_crach,nhl_fight,pig_ball,aikido,angry2,banned,alcoholic,bb2,flood,gamer3,girl_devil,flirt,girl_cray3,girl_drink,girl_hide,girl_hospital,girl_impossible,girl_in_love,girl_mad,girl_sad,girl_sigh,girl_smile,girl_to_take_umbrage,girl_wacko,lazy1,nono,man_in_love,party,scenic,queen,paint,crazy_pilot,dwarf,hang1,haha,grin,good3

好处呢,就是所有的系统配置基本都在这个配置文件中控制即可,无需去各种地方设置了,修改之后重启服务即可。

之所以说是玩具,其实我在wp之外添加了另外一个简单的管理后台,这也是为什么选了django 而没有直接用fastapi。

这个东西最初的目的也不是为了替换wp,所以很多功能也没必要再实现一遍了。基础的操作还是在wp的后台完成。

当然,做完折腾到零点多,补全了一些功能之后,最终还是上线了,这就是目前看到的页面效果,lighthouse测试:

ipv4测试:

ipv6测试:

对于wp的主题,也修改了下页面宽度,与现在的vue的页面宽度基本一致了:

http://zhongxiaojie.com

代码地址:

https://gitee.com/obaby/baby-press-public

百年未有之大变局 —— 硅基崛起

作者陶其
2026年4月24日 11:50

感谢订阅陶其的个人博客!

我这篇博客,名头起的很大,但是也就是聊聊我对近期人工智能发展的看法。

距离上次发布聊人工智能的帖子也快2个月了,上一个帖子还在聊“养虾热”,而现在这个热度早已过去了一个月了,甚至中间还爆发过小规模的“弃养热”。

感觉在这个时代,任何东西的热度基本都不会超过1个月,因为总有新的惹人眼球的事物闪亮登场。

局外人

虽然龙虾被端下来时代的餐桌,但是龙虾带来的自主化的概念被继承了下来。

龙虾之前,无论是DeepSeek还是GPT,都是那种你提问,它回答,然后你再提问,它再回答的问答模式。

而龙虾带来的概念是你吩咐,它分析、操作、验收的全套流程。

人类已经慢慢从AI工具的全程使用者变成了只需提出需求和最终验收的局外人

而且,之前的人工智能模型还需要人类的工程师去不断的调整策略、提供语料、调整算法结构等等;而现在已经出现了利用人工智能去训练新的更智能的人工智能大模型的现象。

也就是说现在的大模型主要靠的已经不是人类去调教进化,而是AI去进化AI,也就是AI自进化。

就像是从单细胞生物慢慢的进化成人类的生物进化的阶段(这里只参考生物进化论,不讨论其他假说),而不再需要外部的造物主的参与了。

之前马斯克就说了一句话(名人名言了属于是):人类只是启动硅基时代的那个启动程序。

这就像是电脑在开机的时候,按下开机按钮后,系统启动之前会需要一段引导程序来引导启动系统,而系统启动成功之后,这段引导程序在本次电脑开机使用期间将不再有任何作用了。

而马斯克认为人类甚至是整个人类时代现在扮演的就只是这段为了唤醒硅基时代的启动程序而已。

也就是说,如果马斯克的设想最终会成立,那么,人类甚至都不再是现在的“局外人”,而是彻底没了作用的旧时代遗物。

届时,赛博朋克里的场景也不是不可能出现,寡头们利用人工智能或者海量机器人狂揽全球财富,底层人民既无法反抗也都没有足够的生产生活资料好好活着。或者出现硅基生命反向领导碳基生命的极限场景。

我杀了我自己

不过,很多人都说马斯克的言论太过激进,这个社会还是以人为本,人工智能发展不过是为了促进人类社会更好的发展。

那么我再从人工智能是促进人类发展的角度再探讨一下。

其实现在企业大范围使用人工智能节省人力成本的事情已经出现了。

无论是企业使用人工智能大量代替原本人类员工的工作岗位,还是现在所谓的将人类员工甚至行业专家蒸馏成skill的事件,无非都是资本为了节省人力成本,转投向成本更低可控性更强可以24小时工作的数字智能的体现。

从最开始的原画师们的失业潮,到现在甲骨文全球大裁员,都是人工智能抢占人类员工岗位的活生生的体现。

而蒸馏已离职员工甚至是去世的张雪峰成为其专属数字skill的事件,这就是赤裸裸的将人类数字化,然后替换真人的体现。

之前科幻电影里都讲到数字永生,将自己的人类意识上传数字空间,虽然现实中的肉体没了,但是意识在数字空间得到了永生。

而现实更残酷,那就是人还活着,但是自己的岗位却被数字化的自己抢了,自己让自己失了业。

典型的“我杀了我自己。”

果然《武林外传》还是太超前了。

人人都是产品经理

还是有人感觉,这个情况还是太过极端。

毕竟被蒸馏或者岗位被数字员工替代,那为什么自己不能借助AI去创业,去闯出一番天地呢?

他们认为,人工智能虽然抢占了一部分人类的现有岗位,但是也解放了人类在重复工作中的束缚,让人类能更多的去思考,去创造,去完成之前以一己之力无法完成的成就。

这一点,我不可否认,也不会去否认。

人工智能确实让人们能完成之前自己所掌握的技能之外的事情。

所以,现在“一人公司”的概念特别的火爆。

就是一个人成立一个公司,但是整个公司就只有自己一个人类,剩下的全都是所谓的“数字员工”,也就是各式各样的拥有专业技能的大模型。

这一点,我们通过数据就能更直观的看出其火爆的市场。

据新闻报道:光安徽省蚌埠市,在2026年一季度,也就是1-3月份,新设一人公司1816户。占同期新设立公司企业总数的74.82%。

这是什么概念?

就是新增一人公司的数量占同期新增总数超2/3了。

那么以蚌埠为基础,不难推理出全国新设多少一人公司,恐怕已是海量。

而那么多的一人公司,能做什么,或者在这个社会能承担什么角色?

针对一人公司,我其实有几个疑问。

1、在商业、经济、科技水平如此动荡的环境下,这些一人公司的抗风险能力能有多少?这不是老板只需要给自己付钱的事情,虽然说是一人公司,但是他所用的所有“数字员工”都是需要烧Token的,也就是烧钱的。如果公司做出来的产品无人使用或者无法产生收益,那么这个公司还能扛下去吗?

2、一个企业的抗风险能力,也决定了这个公司在它客户眼中的可信度和稳定性。而传统认知中,公司只有一个人,那不就是皮包公司么。即使真有东西,可是这个一人公司即皮包公司的观念转变也还是需要时间的。

3、抛弃风险和认知不谈,回归一人公司本身。一个人就意味着容易偏激,这一人公司的老板经过深思熟虑去做的产品,真的就是社会真的需要的产品吗?我想大概率都是老板自认为是好idea的伪需求,这是才是最致命的。老板辛辛苦苦带着一群数字员工做出来的产品,发现社会面根本没市场,自认为的需求完全就是自己一厢情愿的。

这些类似的问题还有很多。

我不会去否认,一人公司中肯定会诞生出非常优秀的产品或者idea,但是那和千军万马过独木桥、一将功成万骨枯有什么区别?

一人公司的老板充其量不过是一个有自主决策权,能指挥“数字员工”完成自己设想的“产品经理”。

这个世界需要优秀的产品,但是却不需要那么多的“产品经理”。

做这种“产品经理”是需要代价的,因为做的数字产品失败了的话,那些代码将一文不值,要知道在AI时代,代码是最不值钱的东西。

失速的时代

其实这个时代真的很矛盾。

  • 一边是促进生育、维持人类数量基本盘;一边是人工智能让人类员工批量失去工作岗位。
  • 一边是隐形的职场社会的35岁“年龄斩杀线”;一边是政策要求延迟退休,希望人们多工作几年;
  • 一边是前沿科技的高速发展;一边是国际社会上为抢能源或者主导权的炮火连天。

其实人们感觉现在日子越来越不好过的原因之一,其实是人工智能发展的实在太快了。

快到人们根本没时间去消化,快到社会根本来不及去诞生对应的新的岗位。

之前的那些次工业革命,无一不是给社会和人们留有足够转型和自我迭代的时间。

可是这次的人工智能大爆发,可没有给予社会和人们那么多时间去反应,技术迭代速度与社会和人们的适应转型速度严重错配。

大模型迭代速度从半年一次到一月一次到现在一周一次。

至于人工智能周边的新技术诞生和陨落也是如雨后的竹笋一般一茬接一茬。

之前新技术出现之后,人们会去钻研、去学习、去应用。

而现在编程圈却流行一句话:只要我学的慢,那么这些新技术还没等学就已经过时了,所以根本不用学,因为学会了也没用,更迭周期太快了。

我不知道,这轮的科技爆发周期什么时候会结束,或者根本不会结束。

直到现在为止,即使人工智能已经如此的侵入各行各业,但是却连一个决定性的划时代的产品也没有诞生。

或许人工智能时代从来不存在什么划时代的产品,而是以润物细无声的方式入侵人们生活工作的边边角角后,如空气一般的隐形,会让人们感觉到的只是自己的手机更了解自己了、自己的生活质量更高了。

超智能的危机

哦对了,我听说无论是OpenAI的奥特曼还是马斯克,这些人都是认为利益大于安全的人,从他们AI团队中安全团队批量离职并抱怨公司高层根本不在乎模型安全就能看出来,相比于大模型带来的利润,他们根本不在乎其可能带来的安全隐患。

除非这个模型已经危急到他们的核心利益了。

比如:Claude Mythos Preview(简称 Mythos)。

就在本月,Anthropic公司向世界宣布,它已构建了一个强大到“太危险而无法广泛发布”的人工智能模型:Mythos,并点名了11家合作伙伴来帮助构建防御体系。

这11家机构全部来自美国。

Mythos 能自主识别全球银行、电网、政府机构运行软件中的隐藏漏洞,其速度和效率远超人类修补的速度。而且Mythos 不仅仅是找出漏洞,还能针对性地生成攻击代码。

因此,它迅速成为一个地缘政治筹码——而握有这张牌的,是一家美国公司。

Anthropic 公司担心该模型被滥用,可能沦为黑客攻击的利刃,所以面向社会停止开放这款模型,但是可没说他们内部或者政府不会去使用这款模型。

OpenAI CEO 山姆·奥特曼将其形容为“一边投炸弹,一边兜售价值1亿美元的防空洞”。

Mythos 是基于逻辑推理与智能体自主决策的全新模型,并非专门的安全分析模型,但在安全领域实现了“代际”飞跃。

……

所以,以后真的可能出现科幻电影小说里的,超级智脑甚至是城市级的智脑吗?

最后的牢骚

一般一篇优秀的文章,在前面提出担忧或者问题并论述之后,在结尾会给出自己的见解或者解决方案。

可是我这一篇,我无法给出所谓的解决方案。

因为我自己也没想明白,在往后无法预估的时代中,采用哪种方式活着才是更正确的。

我也已经达到了31岁,快迈向35岁的门槛。

可是我除了编程技能外,什么都不会。

不是我不愿意去学习,而是根本没方向。

  • 想去深造技术,可是这个时代,人类的学习技术远远赶不上人工智能,代码是最不值钱的东西;
  • 想要转管理,可是一没人脉,二学历也不够,也没大厂经验;
  • 想要转行,可是无论是失业三件套还是其他的技术岗,无一不在人工智能替代的范围内。

男怕入错行,很担心投入精力时间和财力之后学会的技能,下一瞬就被人工智能轻松的代替。

我感觉现在任何超过五年的职业规划或者人生设想都是无意义的,因为现在社会发展太快了,快到超过5年的未来几乎失去了预测的意义。

这才是这个时代人们之所以焦虑的根本性原因,未来已变得不可预测。

之前是人和人的竞争,我只要掌握了一门技术就能安身立命,即使是内卷,大家都是人,你内卷我也能内卷。

可是现在的人工智能完全就是降维打击,你花大量时间辛辛苦苦学会的技能,人工智能只要成功把这个技能提炼成skill,那么就代表着所有模型都会了,而且它还是7×24小时无休。

现在github上有一个项目,里面蒸馏提炼了数百个行业岗位的专业技能成skill,而且数量还在增加。大模型只要配上对应的skill瞬间就掌握了你学习数月甚至深耕数年的行业技能,人类根本毫无还手之力。

希望我们现在还活着的这批人不会是人类最后的绝唱吧。

喜欢百年未有之大变局 —— 硅基崛起这篇文章吗?您可以点击浏览我的博客主页 发现更多技术分享与生活趣事。

人间四月芳菲尽

作者obaby
2026年4月23日 10:07

回到青岛之后,又感受到了阵阵的凉意,从济南的30℃瞬间就到了11℃。与济南的深绿色比起来,青岛的绿还稍显稚嫩,甚至有很多地方的草坪还光秃秃的。

离开济南的时候,天已经变得阴沉沉的。回到青岛,夜里的天空,还能看到弯弯的月亮。然而,看天气预报,这几天也要下雨了。

周一,小雨如约而至,淅淅沥沥的下了一点点。自己上周刚洗了车,约的周二的外景,这一场雨下来,感觉洗也不是,不洗也不是。毕竟如果去拍照的话还是想把粉皮洗的干干净净的。好在周一中午雨就停了,去万达自助洗车,到了之后才发现底下车库施工,暂时停业了。其实自助洗车的地方,上午就给发了短信,以为是垃圾消息一直没点开。现在点开也晚了,路上想着找个洗车的地方洗洗,却发现没有空闲的洗车店,只得暂时作罢。

既然没找到洗车的地方,那就先把快递拿回家吧,卖的粉色小熊这么快就到了,开心。

以前不敢尝试瑜伽裤之类的衣服,毕竟身材实在是太差了,穿起来也挺丑的。虽然现在依然很丑,但是,脸皮厚了也就无所谓了。周二早上送宝子上学,发现学校门口的停车场里的洗车店没人,可能是上午比较早的原因吧。等九点多,刚好就可以从家出门洗车,然后就直接去拍照了,时间这么安排似乎也不错。不过价格你自己洗贵了点,只洗洗外面20块钱,好歹是干净啦,那也就可以了。

周一的时候还怕第二天会下雨,好在周一下午天就晴了。周二虽然没有大太阳,但是光线还算可以。选了两个外景取景地,一个百花苑,一个八大峡。到百花园的时候,路边刚好有个空位就可以把车停下。阴天的小风一吹,还是挺冷的,公园的草坪比济南的也逊色不少,很多地方还是斑驳的黄色,新草还没长出来。即使这样,公园也是成双成对游园的游客。在拍照的树下还有一堆老年夫妇趴在地上看手机,过了会儿看到我在拍照,做起来开始看摄影师拍照。

导航到八大峡的时候,路上导航就提示目标停车场已满,请选择合适的停车场停车。听到提示后,摄影师提议:“我们直接去汐潮观海吧,那边风景好,正好可以拍海,也可以拍公路片。高速费我给你出了。”

“嗐,不至于的,我自己出高速费就行了。”这次因为要拍公路片,所以并没有开摄影师的车,直接自己开车带他们出发了。这次选的外景的服装也比较简单:热裤、短裙、长裙、牛仔裤。所以换衣服也简单,在车上基本就能解决了。

期间发现一件很神奇的事情,carplay 的高德导航在海底隧道时速竟然是对的,竟然不是惯性导航。实际的导航显示速度与时速表竟然是一致的没有显示惯性导航,难道是carplay跟车载系统同步了时速?

到了海边,依然看不到太阳,天色略微阴沉,摄影师说的不错,这里的公路真的出片,稍微带点弯道,两个车道宽度也合适。唯一的问题就是一条超短裙在阵阵海风中没有任何的保暖作用。化妆小姐姐也在海风中冻的涩涩发抖,好在自己还带了个外套,就拿出来给化妆师小姐姐穿上了。

不得不说,这双细跟的鞋子穿起来还是蛮累的。化妆师说,看你走的蛮轻松的,我这种细跟的也就能穿3cm的。

期间拍了几张坐在路上的,不得不说,马路的温度还是不错的,坐在上面能感觉到热乎乎的。

摄影师提议可以坐引擎盖上拍几张,第一次尝试失败了。化妆师小姐姐说:“穿的高跟鞋不太好跳”

但是,我也不是那么容易就认输的人啊,尝试三次之后,终于屁股还是坐到了引擎盖上。不过期间换姿势的时候,听到引擎盖“嘭”响了一声,虽然已经减了很多了,但是看来还是有点重。

等到了海边,风变得更大了,不过好在这次是长裤,能稍微温暖那么一点点。

站在礁石上拍照的时候,海边的观景台上有个大哥拿着手机在拍我,可能想这么冷的天还有人来拍写真,也是腻害。嘎嘎。

本来以为,已经是夏天了,却没想到温度又到了十度。甚至,东北某些地方依然又下雪了。

济南四月芳菲尽,青岛桃花始盛开。

Python中的类和对象

2026年1月20日 00:00

未完待续

1.定义类

python3中的根类,有且只有一个:object(小写)

⚠️大写的Object不存在于python内置中,是自己定义的,为防止混淆不建议使用

__bases__是python中一个内置的变量,代表基类

# 隐式继承,python3自动处理class Cat:    pass# 显式继承class Dog(object):    passif __name__ == '__main__':    print( Cat.__bases__ ) # (<class 'object'>,)    print( Dog.__bases__ ) # (<class 'object'>,)

2.类的成员

2.1 构造方法

  • python初始化类的对象,使用__init__()这个特殊方法作为类的构造方法,创建对象时会被自动调用。
  • python构造方法不支持重载,不能弄多个__init__(),否则最后一个覆盖前面的。

构造方法就是一种实例方法,实例方法第一个参数必须是self代表当前对象

class Cat:    def __init__(self):        print('init')        print(self)        print(self.__class__)if __name__ == '__main__':    cat = Cat()    print(cat)
init<__main__.Cat object at 0x000001982BE1D400><class '__main__.Cat'><__main__.Cat object at 0x000001982BE1D400>

2.2 类和实例的变量

  • 实例变量在构造器__init__中声明,__init__()中通过self.定义实例变量
  • 定义在类以内,__init__()以外的变量是类变量,类似Java中的static
  • 实例变量和类变量不同名时,实例变量通过对象.访问,类变量可以通过类.访问或对象.访问
  • 实例变量和类变量同名是合法但是不推荐的,这种情况下,实例和类会各自有一份,对象.访问到的是实例变量,类变量只能通过类.访问

⚠️__init__()外面的同名变量前面没有static且和self.后面的变量名重名时,self.极易被Java程序员误判为是在为外面的变量初始化或赋值,这种Java的思路,在python中是错误的

例:

  • __init__()里面的重名name,age是实例变量,通过对象.访问
  • __init__()外面的重名name,age是类变量,通过类.访问
  • country变量不重名,可通过对象.访问,也可以通过类.访问
class Stu:    name = 'simaple_name'    age = 0    country = 'China'    def __init__(self, age, name):        print('init')        self.age = age        self.name = name    def speak(self):        print(self.age, self.name)if __name__ == '__main__':    stu1 = Stu(18, '元宝')    stu2 = Stu(20, '大黄')    stu1.speak()    stu2.speak()    print('---------------')    print(Stu.name)    print(Stu.age)    print('-------------')    print(stu1.country)    print(stu2.country)    print(Stu.country)
initinit18 元宝20 大黄---------------simaple_name0-------------ChinaChinaChina

有时候,一个类存在变量过多,逐一用参数赋值会很复杂,例如:

  • def __str__(self)同样是一个内置函数,类似Java中的toString(),打印对象时转换为字符串
  • 双下划线__开头的变量,属于私有变量,类外不可直接访问
class Stu:    def __init__(self, name, age, no, score):        self.name = name        self.age = age        self.no = no        self.__score = score    def __str__(self):        return f'{self.name}, {self.age}, {self.no}, {self.__score}'if __name__ == '__main__':    stu1 = Stu('liming', 16, 10001, 100)    print(stu1)    print(stu1.name)    print(stu1.age)    print(stu1.no)    #print(stu1.__score) ❌错误 AttributeError: 'Stu' object has no attribute '__score'
liming, 16, 10001, 100liming1610001

python是一门灵活的语言!解决这个问题,可以动态的给某个对象设置成员变量,例如为stu2动态指定一个变量no

self.__dict__可以代表对象所有变量

class Stu:    def __init__(self, name, age, score):        self.name = name        self.age = age        self.__score = score    def __str__(self):        return f'{self.__dict__}'if __name__ == '__main__':    stu1 = Stu('liming', 16, 100)    print(stu1)    stu2 = Stu('liming', 16, 100)    stu2.no = '10002'    print(stu2)
{'name': 'liming', 'age': 16, '_Stu__score': 100}{'name': 'liming', 'age': 16, '_Stu__score': 100, 'no': '10002'}

上面的写法不推荐,可以采用定义好再去赋值的写法

class Stu:    def __init__(self):        self.name = None        self.age = None        self.no = None    def __str__(self):        return f'{self.__dict__}'if __name__ == '__main__':    stu1 = Stu()    print(stu1)    stu2 = Stu()    stu2.age = 12    stu2.no = '123'    stu2.name = 'sxh'    print(stu2)
{'name': None, 'age': None, 'no': None}{'name': 'sxh', 'age': 12, 'no': '123'}

还可以通过可变参数

class Stu:    def __init__(self, **kwargs):        self.name = kwargs.get('name', None)        self.age = kwargs.get('age', None)        self.no = kwargs.get('no', None)    def __str__(self):        return f'{self.__dict__}'if __name__ == '__main__':    stu1 = Stu(name='lzj', age=19, no='10002')    print(stu1)    stu2 = Stu(name='xiaohong', age=19 )    print(stu2)
{'name': 'lzj', 'age': 19, 'no': '10002'}{'name': 'xiaohong', 'age': 19, 'no': None}

2.3 成员访问限制

在python中,属性可以进行访问权限控制,和Java类似,如果要访问受保护的属性,就定义方法,这是类封装性的体现

  • 受保护的属性 _单个下划线开头,仅仅起到提醒作用,但是不阻止访问,例如_age
  • 私有属性 __双下划线开头,类外不可访问,否则程序运行出错,例如__age
  • 公开访问属性 没有下划线的,无限制
  • 魔法属性 __双下划线开头和结尾,是python内置的,有特殊的含义,不可自行定义,例如__dict__

⚠️ python处理__双下划线的底层实现,是将该变量替换成了_类名__私有变量名,通过将某个私有变量名修改为_类名__私有变量名的形式,可以突破访问控制,这种访问方式极不推荐

例:

class Stu:    def __init__(self, **kwargs):        self.name = kwargs.get('name', None)        self.__age = kwargs.get('age', None)        self._no = kwargs.get('no', None)    def __str__(self):        return f'{self.__dict__}'    def getAge(self):        return self.__ageif __name__ == '__main__':    stu1 = Stu(name='lzj', age=19, no='10002')    print(stu1)    print(stu1.name)    print(stu1.getAge())    print(stu1._no) #不建议的    print(stu1._Stu__age) #不建议的    #print(stu1.__age) #运行出错
{'name': 'lzj', '_Stu__age': 19, '_no': '10002'}lzj191000219

2.4 静态方法

上面例子里面出现在类中,参数以self开头的方法,都是实例方法,在python中,还存在静态方法和类方法

在python中,有一种方法,只是出现在类中,但是不依赖于实例和类的普通方法,叫做静态方法,采用@staticmethod装饰器装饰,通常都是作为一种工具方法,除非传入否则不能访问类和实例的成员,可以使用实例名或类名调用,但是参数列表中不能出现selfcls

例:def sum(a, b)就是静态方法

class Stu:    def __init__(self):        name = None    def call(self):        self.sum(1, 2)        self.__class__.sum(3, 4)        Stu.sum(5, 6)    @staticmethod    def sum(a, b):        return a + bif __name__ == '__main__':    stu1 = Stu()    stu1.call()    stu1.sum(7, 8)    Stu.sum(9, 10)

2.5 类方法

类方法类似Java中的static方法,python的类方法声明时第一个形参永远是cls代表类本身(不是实例),同时除__new__()以外,所有类方法都要采用@classmethod函数装饰器修饰。

python的类方法既能通过类也能通过实例调用,但是为防混淆不建议用实例调用。

主要用于操作类属性或实现工厂模式。

可直接访问类属性,类方法和静态方法,不能直接操作实例属性或实例方法。

例:

class Stu:    school = 'bupt'    def __init__(self):        name = None    def call(self):        pass    @classmethod    def classfunc1(cls):        print(cls.__name__)        print(cls.school)        cls.sum(1, 2)        cls.classfunc2()    @classmethod    def classfunc2(cls):        print('classfunc2')    @staticmethod    def sum(a, b):        return a + bif __name__ == '__main__':    Stu.classfunc1()    s1 = Stu()    s1.classfunc2()    s1.__class__.classfunc2()
Stubuptclassfunc2classfunc2classfunc2

还可以实现工厂方法,例如:

class Person:    @classmethod    def create(cls, name):        return cls(**{'name': name})    def __init__(self, name):        self.name = nameif __name__ == '__main__':    p = Person.create('lsj')    print(p.name)

2.6 类属性@property

python中,可以定义类属性,类属性是被@property修饰的一种成员,对外表现是变量,对内实现是方法

类属性本身是类的,但是用于实例的属性,可以实现更好的封装

例:

class Stu:    @property    def age(self):        return self.__age    def __init__(self, age):        self.__age = age        passif __name__ == '__main__':    print(Stu.age) #<property object at 0x000001D82AA20D10>    s1 = Stu(29)    print(s1.age) # 29    s2 = Stu(34)    print(s2.age) #34

2.7 其他魔术方法

  • __call__ 让实例对象被当作函数调用

    class Person:    def __init__(self, name):        self.name = name    def __call__(self, age):        self.age = age        return selfif __name__ == '__main__':    p = Person('lsj')    q = p(22)    print(q.name) #lsj    print(q.age) #22

2.8 @dataclass装饰器

@dataclass的用途类似于Java中的Lombok。

@dataclass可以帮我们省略掉__init__()__eq__()__repr__()等常见方法的手写代码,专注于业务逻辑,@dataclass中写的变量名:类型的结构会自动转换为实例变量,自动添加到__init__()中。

@dataclass既能声明带默认值的变量,也能生成不带默认值的变量,无默认值的在前,带默认值的在后。

⚠️@dataclass装饰器会自动生成__init__(),一旦手写了__init__()会导致装饰器失效,所有自动功能全部关闭,如果想用了装饰器又要加自定义的初始化逻辑,用__post_init__(self, ...)避免冲突

例:

from dataclasses import dataclassfrom datetime import date, datetime@dataclassclass Book:    # 类变量:所有书籍实例对象共享    publisher = "机械工业出版社"    id: int = None    bookName: str = None    price: float = None    author: str = None    course_date: date  = None    start_time: datetime = None    # 初始化后校验价格合法性    def __post_init__(self):        print('__post_init__')        if self.price is not None and self.price < 0:            raise ValueError("书籍价格不能为负数!")if __name__ == '__main__':    print(Book.publisher)    book = Book(id = 1, bookName='疯狂python讲义', price=2.3)    print(book)    book = Book(id = 1, bookName='疯狂python讲义', price=-2.3)
机械工业出版社__post_init__Book(id=1, bookName='疯狂python讲义', price=2.3, author=None, course_date=None, start_time=None)__post_init__Traceback (most recent call last):  File "D:\PycharmProjects\python-lang-test\clazz\t3.py", line 27, in <module>    book = Book(id = 1, bookName='疯狂python讲义', price=-2.3)           ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  File "<string>", line 9, in __init__  File "D:\PycharmProjects\python-lang-test\clazz\t3.py", line 21, in __post_init__    raise ValueError("书籍价格不能为负数!")ValueError: 书籍价格不能为负数!

__eq__()的重写,也会导致比较对象时,比较的是成员变量的值,而不是地址

if __name__ == '__main__':    book1 = Book(id = 1, bookName='疯狂python讲义', price=2.3)    book2 = Book(id = 1, bookName='疯狂python讲义', price=2.3)    print(book1 == book2) # True    book3 = Book(id=1, bookName='疯狂python讲义', price=2.3)    book4 = Book(id=1, bookName='疯狂python讲义', price=2.5)    print(book3 == book4) # False

3.对象初始化

python对象初始化o = Obj(),会经历以下几个过程:

1.调用该Obj类的__new__(cls,...)方法,在内存中开辟空间,创建一个空的实例对象
2.__new__(cls,...)执行完成,必须返回一个当前Obj类的实例对象,就是后续的self
3.python自动把返回的对象,传给__init__(self,...)的第一个参数self
4.调用__init__(self,...)给这个空对象绑定属性,初始化数据
5.返回初始化完成的实例对象给变量o

其中:

  • __new__(cls,...)是类方法,但是无需显式添加@classmethod装饰器
  • __new__(cls,...)必须有返回值,返回当前类对象时执行__init__(self,...),返回None则跳过__init__(self,...)
  • __new__(cls,...)的时机一定早于__init__(self,...),先创建再初始化
  • 永远不要出现多个生效的__init__(self,...)

例:

class Person:    def __new__(cls, name):        obj = super().__new__(cls) #调用父类(直到object)的__new__方法开内存空间,        print('new')        return obj    def __init__(self, name):        print('init')        self.name = nameif __name__ == '__main__':    p = Person('liming')    print(p.name)

济南,济南

作者obaby
2026年4月20日 13:29

济南,一个自己待了数年的地方。自己也没想到,等那天真的离开之后,就不再常有去的机会了。上一次去济南还是参加室友的婚宴,一眨眼已经快十年了。

现在,又到了一个春意盎然的季节,宝子虽然已经去过很多的城市,山东省内周边依然都跑遍了,现在剩下的还有靠近最西面的那几个城市。济南,曾经也多次想去转一转,看一看,是不是还是记忆中的样子。然而,却又纠结于出行的便利性,对象总说,去了济南几次,体验印象总是不好。交通差,环境一般,又热。

眨眼时间,感觉年还没过完多长时间,就到了五一了。五一出去玩总是感觉体验更差了。并且,按照济南的温度,等五一的时候就更热了,看那人山人海,总是感觉有些抗拒,最后还是选择了这个周末带着孩子去溜达溜达。

早上七点多高铁,到济南十点多。刚从高铁出来,就开始狂打喷嚏,空气中飞舞的杨树毛毛实在是太多了。从车站出来,本来想打个六座商务,一顿狂奔跑到上车地点,发现竟然是辆出租车。只好让他们先走,自己后面再打一辆车。然而再次打车的时候,发现有进行中的订单,没法打车,好在另外一个手机上还有个滴滴,不然这真就麻烦了。

大明湖畔的夏雨荷?

安顿好,吃过午饭下午就可以出去玩了。对象同学推荐的珍珠泉宾馆,在公园内,出门去哪里都很方便。最终也是选择了这个地方,到了之后找吃饭的地方,也费了一番周章。宝子姥姥这不吃,那不吃,济南小吃把子肉自然是就被排除了。最后选择了一家离住的地方比较近的的全景餐厅。

一顿饭吃下来,除了贵的确没什么优点。羊肉又老又硬,备注不让放蒜的菜,里面还有独头蒜,可能独头蒜不是蒜吧。整体吃下来,就九转肥肠还有佛跳墙勉强可以。其余的几个菜,实在是水平一般。

中午回到住处稍微休息会儿,下午出门的时候从酒店窗户看出去,还以为是阴天了,出门以后发现完全不是,艳阳高照。沿着珍珠泉内部游览,到北门的时候却发现是封闭的,根本出不去,如果要想去大明湖,只能原路返回,从珍珠泉公园围墙西侧绕行过去。

 

这可能只是个普通的周末吧,路上的游人络绎不绝。当然,也有无数穿汉服的小姐姐,只是妆画的稍微浓了点,没那么精致。不过户外拍照可能也好,毕竟室外的光线和环境还是蛮不错的。当然,不精致的好处就是化妆时间可以大大减少,这样就可以多画几个了。

大明湖,最出名的竟然是夏雨荷。一个源自琼瑶小说的人物,这个文创的出发点的确有点让人匪夷所思。济南那么多名人,最后竟然选了一个夏雨荷。上次逛大明湖,还是从厦门回到青岛的时候,带一个姐妹来大明湖转了一圈。只是,从始至终,两个人甚至连一张合照都没有,而现在,也悄然断了联系。

空气中的毛毛,落在草丛里也叠成了厚厚的一层,看上去仿佛下了一场雪。湖中,那个破败的船,不知道是年久失修还是尚未完工,看起来的确也没什么美感,就这么坐落在湖中。

这半圈下来,宝子的姥姥姥爷已经走不动了。带他们出去准备去商场吃饭,顺便对象去给宝子买条裙子。白天玩的时候,一直嚷嚷好热啊,好热啊,跟复读机一样。

母校

他们去逛商场买东西,自己约了在济南的几个室友。准备去学校吃点东西,上次来学校也已然是十多年前了。每次来,总是能看到一些变化,每次来又感觉还是那个样子。

打车往学校走,到处都是修路的影子,从自己第一次来济南感觉就在修路,直到后来离开济南,还是在修路。现在再来的时候,还是在修路,济南的路感觉永远也修不完。路上的电动车自行车浩浩荡荡,在车上我都担心司机可能会蹭到他们。

现在想进校门不再那么方便了,需要校友卡或者提前预约。室友L发了个小程序的链接,好在自己提前注册认证好了。到门口出示校友卡,刷身份证就可以进入了。

从北门进入,现在操场下面是一堆小店,移动、联通等等。路上的道闸一层又一层,不知道是出于什么设计理念。

一路向南,貌似拆了几栋楼,自己原来的宿舍里依然还在,看似来除了外墙稍微新了点,似乎也没什么变化。

_

小树林还是多年前的木地板,稀稀落落的坐着几个人。

还有一个红色的牌子。

只是,现在回家多少有点麻烦。

溜达到快到南门的时候,发现了一个主题邮局,这个貌似之前来的时候还没有。

买了一件粉色的连帽T恤,一个粉色的笔记本,还有那个粉色的小熊。小熊不是很好带,只好让他们帮忙给寄回去。

从南门出来,也已然不是记忆里的样子,对面的书店,现在变得高级感十足。

晚上在学校餐厅三楼点了几个菜,X去买了几瓶rio,算是简单的相聚。晚饭后沿着学校的道路溜达,从南门到北门,操场,教学楼。太多的地方依然不是记忆里的样子。

曾经昏暗的八角楼,现在变得亮如白昼。

南门广场终于也不再是那种绿洼洼的射灯,现在看起来温暖多了。

北门的外卖柜,的确是个高级设计,外面投,里面取。S说,这可以说是这个学校最伟大改进。

路过宿舍楼的时候,听到两个小情侣在闹分手。

女:我想分开一段时间。

男:想分就分吧,我不觉得自己有什么问题,我觉得我做的挺好的,你想跟谁就跟谁吧。

女:不是这个意思,……

我跟L说,那俩分了,你去不领一个走?

X问:啥要分了?

我说:后面那俩在闹分手呢。我简单复述了一下他们的对话。

X说:这叫极限拉扯,在追求自己的利益呢。

我说:能干就干,不能干就滚呗!

L大惊:啥意思?

我的意思是,能过就过,不能过就分。这种自认为完美无瑕的男人,我要是那个女生,早就撒丫子跑了。我忙解释道。

X说:你头一直这么铁吗?

不不不,我上学的时候也是傻逼。还没经受过社会毒打,经过社会毒打之后才变得这么铁的,哈哈哈。我回道。

快出校门的时候,X说,你们等一下,我去骑我的小电动。

我跟L刷卡出去,站在外面看路边的标牌。我说:『刚看这个网吧,我还想什么沙雕名字,墨迹网咖,咋地越打越墨迹?后来才发现我看错了,是星迹网吧。』

『你还是那么幽默』L说,的确,我这不认字、以及看错顺序的毛病不是一天两天了。

X过了十几分钟从道闸出来,说:『刚才被吓一跳,一个男生在大马路上去找一个女生要微信,被无情的拒绝了!』

『现在还流行这么要联系方式吗?如果找我要,我也不给!』我说。

趵突泉

这也是济南必去的景点了,来都来了,怎么能不去呢。早上一早起来就奔趵突泉而去,这次尝试只选商务,然而,很不幸根本没有。最后还是打了一辆出租车。他们走了之后自己解锁了一辆共享单车骑过去。在路上这自行车道有的在辅路的左侧,有的在右侧,直接整懵逼了。

趵突泉树上的牌子写着:『再喂就嘎了』,意思是已然不让投喂锦鲤。实际情况也是并没有人投喂,然而对象在入口给宝子买了六包小鱼食,最后终于在一个比较偏的小河中,找到一群小金鱼,把鱼食投喂了出去。

再出发之前就看到有人发的把子肉味的酸奶,这下也总算是体验到了。

感觉是一股咸肉粽的味道,腻歪歪。不过那个荷叶味道的还是蛮清新的。

相比大明湖,趵突泉就小多了,用了个把小时转悠一下就准备下一站了。博物馆,当然,很多人都觉得写的是山东情妇馆。

 

鉴于上午退房之后,现在有三个大背包,想着找个储物柜存起来。去发现所有的储物柜都是满的。进去之后,发现包里有自拍杆,保安提示可以把自拍杆寄存到保安室,这下正好就可以把其他的几个包寄存了,省下一个带笔记本的,怕万一有点什么事情也不好处理就背在身上。

从四层一层层的往下走,当然主要是为了看现眼包文物。那个青铜首饰盒上面的两个小人是全裸的,嗯嗯,这就蛮有意思的。关键是,那个小男人,JJ绷的又长又直。

看到那根巨长的胫骨,我跟我对象说,它好长啊,我感觉比我的骨头长,我的也就两扎多点,那个至少得有三扎,我得拍下来。

一层层转下来,已经是下午一点,隔着一个街区,路过美术馆就到了万象汇,所有的饭店都在排号,想着找个排队少的,也挺难的。趁他们在等椰子鸡的时候,自己去溜达了一下,找到一个北京羲和烤鸭,刚开始还想,这義和烤鸭,我第一个想到的竟然是义和团。等了十几分钟,大桌叫号之后自己进去等,给他们打电话通知过来。想着叫义和烤鸭总是有点不对,只是告诉他们是北京烤鸭。对象来了之后,我说,这义和烤鸭名字是不是有点那啥,让我想到了义和团。对象说,我也是,第一眼这么像的,后来发现不是,是羲和烤鸭,你看盘子上。

仔细观察才发现真的是羲和烤鸭,得被没吆喝说让他们来义和烤鸭。

完善的火车,下午依然有足够的时间。刚好就可以去路过的美术馆了。虽然没啥美术细胞,但是看看嘛,总也是好的。

一楼的问道,一不小心,就问到了三楼。

其他的就是各种美术展,陶瓷展,属于自己看不懂的犯愁了,唯一能看懂的就是这个万花筒。

离开的时候,又经过门口的那个雕塑,还是忍不住拍了下来。

这光屁股的男人,身材是真的好,头上顶个蛋,抬着头,双手捂着私处。

这雕塑难道是想告诉我:别折腾了,折腾来折腾去,有个蛋用啊!

 

使用Filebeat采集Nginx日志到ES

2026年4月18日 00:00

filebeat是传统elk组件中logstach的升级替代,能够高性能的采集一些中间件的日志到es中,供检索分析。

1.安装filebeat

首先要安装filebeat到nginx所在服务器,因为我的服务器是rocky linux属于redhat系,故这里通过yum安装,先设置安装源

导入GPG-KEY

rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

新建一个elastic.repo文件在/etc/yum.repos.d下,并粘贴安装源地址

vim /etc/yum.repos.d/elastic.repo

[elastic-9.x]name=Elastic repository for 9.x packagesbaseurl=https://artifacts.elastic.co/packages/9.x/yumgpgcheck=1gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearchenabled=1autorefresh=1type=rpm-md

接下来执行安装,直到安装完成

yum install filebeat -y

2.设置nginx和filebeat

首先确认nginx的日志路径和日志格式,一般日志路径默认就是:

  • /var/log/nginx/access.log 常规访问日志
  • /var/log/nginx/error.log 错误日志

在nginx.conf配置文件中,默认的日志格式是:

log_format  main  ' $remote_addr - $remote_user [$time_local] "$request" '                  '$status $body_bytes_sent "$http_referer" '                  '"$http_user_agent" "$http_x_forwarded_for"';

为了区分各个主机的访问记录,我选择增加一个主机的字段:$host

log_format  main  '$host $remote_addr - $remote_user [$time_local] "$request" '                  '$status $body_bytes_sent "$http_referer" '                  '"$http_user_agent" "$http_x_forwarded_for"';

亲测filebeat可以识别上述的日志格式,自动提取有效信息

然后设置filebeat,通过yum安装的filebeat,默认全局配置文件位于/etc/filebeat/filebeat.yml,有这样几项需要修改

output.elasticsearch:  # 改成自己es地址和端口  hosts: ["localhost:9016"]  # 改成自己的索引格式  index: "nginx-logs-%{+yyyy.MM.dd}"  # 通信协议按需要修改  protocol: "http"  # es用户名密码,必须设置  username: "elastic"  password: "***************"# 需要新增这两项,索引数据格式模板名称setup.template.name: "nginx-logs"setup.template.pattern: "nginx-logs-*"

然后对nginx的采集功能进行设置,filebeat支持很多中间件的日志采集,通过yum安装的filebeat,默认的各中间件的采集配置文件位于:/etc/filebeat/modules.d/

首先要将默认的nginx配置文件nginx.yml.disabled复制出一份nginx.yml,因为最后filebeat只会自动导入读取.yml结尾的文件

cp /etc/filebeat/modules.d/nginx.yml.disabled /etc/filebeat/modules.d/nginx.yml

vim编辑/etc/filebeat/modules.d/nginx.yml配置文件,针对nginx的采集进行配置

- module: nginx  # 打开常规访问日志采集,指定日志路径  access:    enabled: true    var.paths: ["/var/log/nginx/access.log"]    var.timezone: "Asia/Shanghai"  # 打开错误日志采集,指定日志路径  error:    enabled: true    var.paths: ["/var/log/nginx/error.log"]    var.timezone: "Asia/Shanghai"

都修改完成后,通过filebeat test config命令,验证配置文件是否有语法错误

[root@VM-0-3-rockylinux ~]# filebeat test configConfig OK

然后启动filebeat,并且能看到进程,启动成功

[root@VM-0-3-rockylinux ~]# systemctl start filebeat[root@VM-0-3-rockylinux ~]# ps -ef | grep filebeatroot      279214       1  0 Apr17 ?        00:00:09 /usr/share/filebeat/bin/filebeat --environment systemd -c /etc/filebeat/filebeat.yml --path.home /usr/share/filebeat --path.config /etc/filebeat --path.data /var/lib/filebeat --path.logs /var/log/filebeatroot      484905  454652  0 14:33 pts/2    00:00:00 grep --color=auto filebeat

3.查看索引

登录kibana,打开开发工具,就能看到filebeat建的索引和采集到的日志了,还可以根据业务需要制作图表等

还可以通过检索,通过链接和访问次数进行聚合,查出一些攻击和刺探的恶意请求,例如:

GET /nginx-logs-2026.04.18/_search{  "size": 0,   "aggs": {    "domain_counts": {      "terms": {        "field": "url.domain",       "size": 20000      },      "aggs": {        "domains_per_ip": {          "terms": {            "field": "source.ip",            "size": 20000                      },          "aggs": {            "domains_per_path": {              "terms": {                "field": "url.path",                "size": 20000                              }            }          }        }      }    }  }}

偷梁换柱 — 解决『出境易暂不支持此应用。』

作者obaby
2026年4月17日 15:30

前几天去买手机的时候,销售小哥说,如果你不喜欢这个纯血鸿蒙,或者感觉无法满足需求可以回来去二楼,找技术把系统进行降级。

当时我在想:对于我这种买手机不怎么玩游戏或者需求没那么多的人来说,应该能解决我的绝大多数需求,毕竟系统上还有 出境易、卓易通。

然而事情总有例外,自己常用的浏览器vivaldi发现竟然无法安装,这就让人非常的抑郁了。

下载apk安装的时候提示:出境易暂不支持此应用。

哎,咱们可不兴这么搞啊,这就离谱啦。我已我不稳定的智商来猜测这个东西肯定是有个神马白名单或者黑名单机制,至于黑白名单,到时也没那么关键,大不了就改个包名嘛。然而安装 apktool m的时候同样的提示也出现了,这个东西大概率就是黑名单了。

算鸟,算鸟,直接用模拟器改吧:

点击快速编辑:

原来的包名:com.vivaldi.brower,咱们假装是uc咋样呢:

反正我也不用uc浏览器,嘎嘎。

修改之后,发送到手机进行安装,一切顺利,嘻嘻:

鸿蒙next:我要验牌!牌没有问题!

尝试同步功能:

完美!

到这里就结束啦,对于同步问题,有的宝子说非得搭梯子,也不一定。可以直接修改hosts,可以在路由器配置或者dns配置,或者神马别的地方配置:

vivaldi.com. 172.66.165.60
bifrost.vivaldi.com. 31.209.137.10
cdn.jsdelivr.net. 151.101.89.229

 

生日快乐 — 又是一年二十九

作者obaby
2026年4月16日 13:52

年复一年,时间似乎过的很快,又过的很慢。今天一直在忙各种事情,直到现在才有片刻的空闲,来庆祝下自己的生日。

这一年发生了很多意料之外的事情,甚至有的事情到现在还没有结论,后续如何更是一个未知数。然而,不管如何,生活还是要继续的。这慢慢人生,没有太多的时间去彷徨,去挣扎,去苦闷。

好几天之前,刷到一个视频,我跟对象说,我要把这个在我生日那天发朋友圈,之前保存下载,今天早上就出现在了自己的朋友圈了,虽然没人点赞,没人回复,我倒是也不在乎,自己开心就好。

至于生日礼物,上周的时候对象就问自己想要什么。

『我要三折叠』

『没有』

『我要双折叠』

『也没有』

对于这种折叠屏手机,只是没用过,有点喜欢,可能也没那么喜欢。昨天中午,趁着午饭的时间,去乐客城外面的华为体验店看了一眼。

只是出来之后,原来的华为竟然变成了小米。高德搜了一下发现地标还没变,但是在其他的地方有另外两个,只好往另外一边的华为体验店走。

中午时间,店里没几个顾客,连店员都没几个。看了下三折叠跟双折叠,三折叠太贵,双折叠的尺寸总是觉得有些奇怪。

双折叠的感觉就是叠起来,打开比例看着都挺奇怪的。三折叠的价格,实在是不敢恭维,快两万块钱买个手机,这已经远远超出自己的可承受范围了。走之前给对象发消息,得到了明确答复,坚决不同意买三折叠。

最后,目标还是落在了mate 80 和pure 80上,至于mate,那个中间的摄像头总是感觉有些别扭,店员还说,那个特别商务,看起来比较大气。问题是,我不喜欢商务风啊。

鉴于线下还能领国补,虽然没有自己想要的金色,还是果断下单了,最终选的的白色,黑色也不喜欢。

还给了一堆乱七八糟的赠品,聊胜于无吧。

之前的p70 pro彻底放弃了,而至于30,也的确支撑的有点吃力,至于90,新机价格大概率比较贵,所以现在马上换代了,80 就80吧。

晚上回家的时候,收到了对象送的猫和老鼠的小手办,老鼠被压成鼠饼的那一集,嘻嘻。

中午的时候,买的新的车载空气清新剂和另外一条瑜伽裤到了,之所以再买一条是感觉上一条的弹力不够大,跳绳的时候没有足够的压力支撑。

上面是原来的,现在已经没什么味道了、下面是新买的。

味道还是蛮清新的,喜欢女生味的可以考虑下哦,香型:香奈五号。香奈儿的就不考虑了哈,那个太贵了,很多仿这个香味的。

比原来的大一圈,放到前面的杯架刚刚合适。

至于瑜伽裤,感觉弹力的确比上一条要好一些,价格也自然是贵了点,上一条黑色瑜伽裤的两倍。

上身效果:

最后,贴一下现在的手机壁纸,希望锦鲤给所有人都带来好运哦:

我要赚钱钱 我要暴富富
我要变美变瘦变酷酷
我要钱多多 我要买车车

Chrome浏览器自带翻译的诡异Bug:ID翻译后竟然变化了

当前负责的项目主打海外业务,总免不了和多语言打交道。但最近我在Vite+Vue3+Element Plus技术栈的项目里,遇到了一个堪称“玄学”的bug——Chrome浏览器自带翻译功能,居然能把表格里的数字ID直接改了!从印度同事到国内运...

❌