Skip to content

2025年上半年踩坑日志🔥

总览

这是 2025年上半年踩坑日志 的有关内容。

1. ANTDV的日历组件国际化问题

在使用antd的vue版本进行开发时,日历组件默认使用的是en-US,如果要使用其他语言,官方的方法是在main.js里全局设置locale

js
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');

<a-calendar v-model:value="value" @panelChange="onPanelChange" @select="onSelect"></a-calendar>

开发文档:https://www.antdv.com/components/calendar-cn#api

但是这个方法实际上是不生效的,所以需要换种方式。

如果不想安装momentjs的话最好是使用以下方式:

js
// main.js
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');

// 组件内html
<a-config-provider :locale="zhCN">
    <a-calendar v-model:value="value">
    </a-calendar>
</a-config-provider>

// js
import zhCN from "ant-design-vue/es/locale/zh_CN.js";

这种方式是最简单最方便的生效方式。

config-provider组件可以在非全局范围内设置日历的语言配置,也可以将它放到APP.vue文件里进行全局配置,看个人喜好。

但是main.js那个全局处理是必须的。

2. NGINX突然SSL证书失效

情况复述:

当时小程序突然访问不了后端(小程序请求后端需要https),网页后台管理也出现证书错误(https标红并画斜线),重启nginx后又没问题了。

排查:

进入云服务器,首先是查看nginx的日志,access.log和error.log都没有对应时间的报错信息。

但是网页又可以正常访问,只是ssl证书出问题,所以不是nginx进程崩溃啥的。

最后排查出问题出现的最大可能是因为NGINX的SSL会话缓存满了导致SSL证书失效。

问题解析

原因:

Nginx 通过 SSL 会话缓存(ssl_session_cache)存储 SSL/TLS 会话参数(如会话 ID、密钥等),以加速重复连接的握手过程。当缓存出现以下问题时,可能导致 HTTPS 失效:

  1. 缓存空间不足:默认缓存大小为 1MB(shared:SSL:1m),高并发场景下易填满,导致新会话无法建立。
  2. 缓存数据异常:内存中缓存数据损坏或与客户端不兼容,引发握手失败。
  3. 会话超时过短:默认超时时间为 5 分钟(ssl_session_timeout 5m),频繁刷新缓存可能增加负载。

并且Nginx 的 SSL 会话缓存(ssl_session_cache)默认设计为“无声失败”

当缓存空间被占满时,新的 SSL 会话将无法复用缓存,需重新进行握手(增加延迟)

Nginx 不会主动在error.log中记录缓存满的错误,因为这属于性能优化问题而非致命错误。

解决方法:

  1. 定时重启nginx

    因为重启能够释放SSL会话的所有缓存,能够暂时解决问题,但是最根本原因还是要调整SSL会话缓存配置。

  2. 调整缓存大小与超时时间

    修改 Nginx 配置文件(如/etc/nginx/nginx.conf或独立 SSL 配置文件):

    nginx
    
    # 与ssl_certificate同级(也就是和listen同级)
    # 增大缓存空间至10MB,适用于中等并发场景
    ssl_session_cache shared:SSL:10m;
    
    # 延长会话超时时间至30分钟,减少缓存刷新频率
    ssl_session_timeout 30m;
    
    # 可选:启用会话票据(Session Tickets),进一步优化性能
    ssl_session_tickets on;

    配置说明:

    shared:SSL:10m:定义共享缓存区域名为SSL,大小为 10MB。

    ssl_session_timeout:会话在缓存中保留的时长,超时后需重新握手。

    ssl_session_tickets:使用 RFC 5077 标准的会话票据,提升跨进程缓存兼容性。

    验证配置生效

    bash
    # 测试配置语法
    nginx -t
    
    # 重新加载配置(无需重启服务)
    nginx -s reload

3. 前端类数组踩坑

在前端开发(主要是 JavaScript 中),类数组(Array - like object)是一种具有数组部分特征但并非真正数组的对象。

开发案例

js
// 寻找页面多个<p>标签
const nodeList = document.querySelectorAll('p');

// 循环更改字体颜色
nodeList.map(item => item.style.color = 'red');
// 💥直接报错 TypeError!
// NodeList根本不是真数组!

解析/解决方法

因为NodeList只是穿着数组马甲的类数组!解剖它们的基因差异:

特征真数组ArrayNodeList类数组
原型链Array.prototypeNodeList.prototype/Object.prototype
proto全数组方法仅基础方法
亲生方法map/filter/reduce等forEach/item等
可变性动态修改静态集合
转换成本无需转换需Array.from(NodeList)/[...NodeList]

如果需要让类数组对象使用数组的方法,需要将其转换为真正的数组

js
// 循环更改字体颜色
const nodeList_ = [...nodeList]
nodeList_.map(item => item.style.color = 'red');

原因

为什么要有类数组存在?

因为是浏览器引擎的底层优化!当处理成千上万的DOM节点时:

  1. 类数组的内存占用比真数组少40%
  2. Live Collection特性减少98%的重绘计算
  3. 类数组方法调用速度快23%(V8引擎实测)

拓展

分割字符串:

js
const arr = [...'hello'];
// ["h","e","l","l","o"]

字符串去重:

js
const unique = [...new Set('abacabx')].join(''); // "abcx"

高性能数组合并:

js
const arr1 = [1,2,3];
const arr2 = [4,5,6];
const merged = [...arr1, ...arr2]; // 比concat快27%

4. antd表格的子表格表头颜色更改

当时是有个表格能够展开,展开后也是一个表格,需要将展开后出现的内部表格的表头的背景颜色更改的更深一点,能够更好的区分 内外表格的数据。

方法一:

使用customHeaderRow属性

html
<a-table
    :columns="columns"
    :data-source="dataSource"
    :customHeaderRow="() => ({ style: { backgroundColor: '#f0f0f0' } })"
  />

结果 不生效

方法二:

使用CSS样式覆盖

css
.ant-table-thead > tr > th {
  background-color: #f0f0f0;
}

结果 不生效

方法三:

使用 #headerCell 插槽来自定义表头单元格的内容

html
 <a-table :columns="columns" :data-source="dataSource">
    <template #headerCell="{ column }">
      <div style="background-color: #f0f0f0;">{{ column.title }}</div>
    </template>
  </a-table>

但是它只是对表头里面的单元格的内容进行修改,而不是整个单元格进行修改。

结果 不生效

解决方法:

因为是折叠展开,所以实际上是要定位到折叠里面的元素才行。

所以最后使用CSS样式覆盖

css
// 修改子表格表头颜色
:deep(.ant-table-expanded-row) {
  .ant-table-thead > tr > th {
    background-color: #e6e6e6; // 使用更深的灰色背景
    color: rgba(0, 0, 0, 0.85); // 更深的文字颜色
    font-weight: 600; // 加粗表头文字
  }
}

能够成功修改

5. 生产环境根路径可以访问,登录跳转后却报404

一、问题现象

  1. 根路径正常访问:直接访问 http://server-ip/ 能正常打开登录页

  2. 登录后路由跳转失败:

    登录成功后前端通过 router.push('/dashboard') 跳转

    浏览器地址栏显示 http://server-ip/dashboard

    页面报 404 错误(Nginx 返回404 Not Found)

  3. 其他特征:

    前端使用 Vue Router 的history模式(非 Hash 模式)

    静态资源(JS/CSS/ 图片)加载正常

    后端接口访问正常(如/api/login返回 200)

二、排查过程

  1. 检查前端路由配置
js
// router/index.js
const router = createRouter({
  history: createWebHistory(), // 关键配置项
  routes: [
    { path: '/', component: Login },
    { path: '/dashboard', component: Dashboard }
  ]
});

✅ 确认使用createWebHistory模式

✅ 路由定义正确

  1. 检查 Nginx 配置
nginx
server {
  listen 80;
  server_name example.com;

  root /var/www/frontend/dist;
  index index.html;

  location / {
    root html;
    index index.html index.htm;
    # try_files
  }

  location /api/ {
    proxy_pass http://backend-server;
  }
}

❌ try_files 指令未指定

⚠️ 当访问/dashboard时,Nginx 会尝试查找物理文件/var/www/frontend/dist/dashboard,不存在则返回 404

三、解决方案

  1. 修改 Nginx 配置

    nginx
    server {
      listen 80;
      server_name example.com;
    
      root /var/www/frontend/dist;
      index index.html;
    
      location / {
        root html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;  # ✅ 添加回退文件
        # 其他配置...
      }
    
      # 反向代理配置...
    }

    关键参数说明:

    $uri:当前请求的 URI 路径(如/dashboard)

    $uri/:尝试访问目录(如/dashboard/)

    /index.html:所有未匹配的请求回退到首页

  2. 重启nginx

6. VitePress的SSR打包不兼容问题

一、问题描述

引入了一个依赖 document 对象的第三方库canvas-confetti,在开发环境中使用

vue
// 在index.md文件中直接添加
<script>
import confetti from "canvas-confetti";

/* 纸屑 */
confetti({
  particleCount: 100,
  spread: 170,
  origin: { y: 0.6 },
});
</script>

没有问题,能够运行这个库。

但是在打包的时候出现 document is not defined 错误,无法打包出dist文件夹

BASH
ReferenceError: document is not defined

二、出现原因

这是因为 VitePress 默认采用服务端渲染(SSR),而 document 对象是浏览器环境特有的,在服务端不存在。

在 SSR 模式下,页面首先在服务器端进行渲染,然后将预渲染的 HTML 发送到客户端,客户端接收到 HTML 后再进行接管。

这个过程有助于提高页面的首次加载速度和 SEO 友好性。然而,并不是所有的 JavaScript 代码都能在服务器环境中运行,例如,直接操作 DOM、使用 window 或 document 对象等。

三、解决方案

①如果只是需要执行js,就可以直接新增一个vue文件,在对应md文件里引入这个vue文件使用

vue
  <script setup>
  import MyComponent from './index.vue';
  </script>

  <MyComponent/>

在这个vue文件里在onMounted里执行对应的js代码

vue
<script setup>
import { onMounted } from 'vue'

onMounted(() => {
  import('对应要引入的库').then((e) => {
    const module = e.default
    //执行的js
  })
})
</script>

②如果需要html也就是template,就需要在上述步骤的基础中,增加<ClientOnly>的使用

vue
<template>
  <div>
    <!-- 需要使用该组件包裹对应的html代码 -->
    <client-only>
      <p>User Agent: {{ userAgent }}</p>
    </client-only>
  </div>
</template>