Skip to content

2024年踩坑日志

1. 服务器时间问题

后端需要调用第三方接口,第三方接口又有5秒钟时间差的限制,在本地环境不会有问题,但是部署到云服务器上就会请求出错。因为云服务器的系统时间和真正的本地时间是有差距的,这个差距不是一两秒,而是一两分钟,导致请求出错,但是云服务器的硬件时间又是准确的。

所以最后的解决方式是在云服务器里设定个定时任务,定时将系统时间与硬件时间同步

2. 公众号文章问题

原本客户想要在小程序上展示公众号文章,后面小程序链接公众号成功后,发现拿不到那么多文章。

后面了解到是微信小程序那边没有对应的接口,因为公众号的文章是分为群发发布两个类型。

如果文章是群发类型,就拿不到对应的公众号文章数据,因为微信没有提供群发类型文章接口,只提供了发布类型的文章接口,而因为群发类型会自动通知到关注公众号的用户,所以一般发布者都会设定成群发类型,导致拿不到数据。(纯微信的问题,一直没接口)

最后只能取消这个需求,除非是客户愿意将群发文章都重新写一遍变成发布类型文章。

3. 微信公众号文章在小程序展示

如果一个微信公众号文章想要在小程序中展示,需要与小程序进行绑定关联,这样才能在小程序的web-view组件里展示文章内容。

不然就会出现无法打开该页面无法打开该图文信息的错误提示。

可以使用反向代理的方式,中间加一层代理,将公众号文章的内容转发到小程序里。

但是这个代理需要有中间的服务器或者nginx来做,而且如果公众号文章里有图片的话,因为微信对公众号文章里的图片做了防盗链,所以展示不出来。

因为web-view组件的限制,所以只能展示文字内容,也无法拿到文章的html结构,无法改里面图片元素的地址。

目前用nginx做反向代理的话,是无法解决这个防盗链问题。也许用后端接口的方式可以解决这个问题,但是实现起来会比较麻烦,所以暂时没有尝试。

4. 上传文件post请求报400

如果不是用ui库自带的upload组件里的action方式上传文件,而是采用自己post请求方式,会出现400错误。

明明在请求头已经"Content-Type": "multipart/form-data",但还是报错。

javascript
fetch('/api/upload', {
    method: 'POST',
    body: fd,
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  })

而这个解决方法就是移除"Content-Type": "multipart/form-data"

使用post 请求上传文件的时候是不需要自己设置 Content-Type,会自动给你添加一个 boundary ,用来分割消息主体中的每个字段,如果这个时候自己设置了 Content-Type, 服务器就不知道怎么分割各个字段,因此就会报错。

5. 前端播放视频问题

前端video标签使用后端接口请求视频时,有些MP4视频会出现一直请求失败的情况,是因为默认浏览器是识别H264编码格式的MP4视频,但是如果后端给的是H265编码格式的MP4视频,前端就无法识别,导致一直请求,一直失败的情况。

要么就前端上传视频做个限制,使用mp4box.js查看上传文件的编码格式是否为H264;要么就后端进行处理,将上传的所有视频统一采用FFmpeg进行转码成H264的mp4视频,但是这样很吃后端服务器的性能,而且不同服务器视频转码的时间也不同,所以我这边采用的是前者限制上传文件的方式。

javascript
const checkMp4Mime = async (file) => {
  return await new Promise((resolve) => {
    if (file.type == "video/mp4") {
      const reader = new FileReader();
      const buffer = reader.readAsArrayBuffer(file);
      reader.onload = async function (e) {
        let arrayBuffer = e.target.result;
        arrayBuffer.fileStart = 0;
        const mp4boxfile = MP4Box.createFile();
        mp4boxfile.onReady = (info) => {
          const mime = info.mime;
          const codec = mime.split("; ");
          let res = false;
          codec.forEach((item) => {
            if (item.indexOf('codecs="') > -1 && item.indexOf('avc') > -1) res = true;
          });
          if (res) {
            resolve(true);
          } else {
            resolve(false);
            window.$notification.warning({
              message: "只能上传编码格式为H264的MP4视频",
              description: "浏览器播放mp4视频只支持H264编码格式",
              duration: 5,
            });
          }
        };
        mp4boxfile.appendBuffer(arrayBuffer);
      };
    } else resolve(true);
  });
};

6. 后端视频文件接口

如果是直接使用IO流去传输视频文件,那么前端得等整个视频文件下载完成才会去播放,当视频很大的时候,就需要等待很长的时间才能播放起来,而且对服务器的带宽压力也很大。

所以后端需要采用静态资源请求处理器ResourceHttpRequestHandler

实现代码在功能实现--静态资源请求处理器

7. pkg打包nodejs程序为exe文件会出现的问题

打包时会出现报错,这些太多就不说。在打包完exe文件后,在运行过程中,会突然卡死,但是按enter能够继续接着之前的程序运行。

是因为CMD的属性设置为Quick Edit Mode和Insert Mode,当“不小心”鼠标点击页面,让CMD认为需要等待输入,则会陷入“卡死”,按下Enter让CMD任务输入完成继续输出显示程序的运行结果。

image.png

取消勾选Quick Edit ModeInsert Mode这两项,解决这个问题

image.png

8. 前端项目打包后注意事项

前端项目一般来说打包后会出现dist文件夹,里面就是整个项目打包压缩好后的三件套文件(html+css+js)

但是不能直接双击打开index.html来展示前端,因为在开发环境中,资源文件的引用路径通常是相对于当前运行的服务器根目录的。然而,当你直接通过文件系统协议(file://)打开index.html时,这些相对路径可能无法正确解析,尤其是当资源文件位于index.html所在目录的子目录下时。

而且还因为同源策略的限制,css和js对于这个index.html来说是不同源的资源,所以也无法获取到,导致整个页面白屏。

还有就是异步请求,在开发环境时会有代理,但是打包是不会将代理一起打包进去,所以会跨域。

为了避免这些问题,正确的做法是在本地启动一个简单的HTTP服务器来托管dist文件夹中的内容。这样可以确保资源路径正确解析,同时避免跨域限制,使得动态加载资源的请求能够被正确处理。

9. springboot请求第三方服务器返回数据乱码问题

一般是因为第三方服务器返回的数据编码格式不是UTF-8导致的。

所以需要限制第三方服务器返回数据的编码格式。

springboot一般用restTemplate来请求第三方服务器,只需要在请求前添加以下代码即可。

java
// 请求前手动设置UTF-8编码解析报文体
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));

这样从第三方请求回来的数据就是UTF-8编码的了,没有乱码问题。

tips

如果请求头使用的是application/x-www-form-urlencoded,那么就需要在请求前手动设置Content-Typeapplication/x-www-form-urlencoded

java
// 创建HttpHeaders对象并设置多个请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

如果传参使用的是Map,那么就需要将Map转成MultiValueMap

java
MultiValueMap<String,Object> params = new LinkedMultiValueMap<>();
params.add("name","小明");

10. Git Commit 提交代码如何取消代码校验

使用别人的项目进行二次开发时,一般会将代码上传到自己的仓库当中进行保存。

在提交代码时,因为某些项目会有设定好的代码校验规则,有时候会出现代码校验失败的情况,这时候就需要取消代码校验。

在提交代码时,加上--no-verify参数即可。

bash
git commit -m "提交代码" --no-verify

如果不想次次上传代码都加上这个参数,也可以采用以下方法:

进入.git/hooks文件夹,将hooks文件夹中的所有文件删除!直接删除全部的文件,不要删除文件夹。

再重新执行代码提交commit就不会有代码校验的问题了。

11. Vscode的终端无法使用pnpm命令

在vscode终端里使用pnpm命令时,会提示pnpm : 无法加载文件 D:\Program Files\pnpm\pnpm.ps1,因为在此系统上禁止运行脚本

解决方法:

在vscode终端里执行以下命令:

bash
#更改vscode终端的状态
Set-ExecutionPolicy RemoteSigned

然后再执行pnpm命令就可以了。

记得将pnpm远程仓库设置成镜像仓库地址:

bash
pnpm set config registry https://registry.npmmirror.com/
pnpm set registry https://registry.npmmirror.com/

解释:

Set-ExecutionPolicy RemoteSigned 是一个 PowerShell 命令,用于更改 PowerShell 脚本的执行策略。这个特定的设置允许你运行本地创建的脚本,而从 Internet 下载的脚本必须有一个数字签名才能运行。

这里是各种执行策略的简要概述:

  1. Restricted:这是默认设置,不允许运行任何 PowerShell 脚本。

  2. AllSigned:只允许运行经过数字签名的脚本。

  3. RemoteSigned:允许运行本地创建的脚本。从 Internet 下载的脚本必须有一个数字签名才能运行。

  4. Unrestricted:允许运行所有脚本。

12. localstorage可以多页面通信,但是sessionstorage不行

MDN的解释中:

只读的localStorage 属性允许你访问一个Document 源(origin)的对象 Storage;存储的数据将保存在浏览器会话中。localStorage 类似 sessionStorage,但其区别在于:存储在 localStorage 的数据可以长期保留;而当页面会话结束——也就是说,当页面被关闭时,存储在 sessionStorage 的数据会被清除。

所以localStorage是可以多页面通信的。

那么sessionStorage呢?

  1. 页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话。
  2. 在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,这点和 session cookie 的运行方式不同。
  3. 打开多个相同的 URL 的 Tabs 页面,会创建各自的 sessionStorage
  4. 关闭对应浏览器标签或窗口,会清除对应的 sessionStorage

sessionStorage 不能在多个窗口或标签页之间共享数据,但是当通过 window.open 或链接打开新页面时(不能是新窗口),新页面会复制前一页的 sessionStorage

sessionStorage 就是会话级别的存储(关键在于会话)

如何定义一个会话?

在A页面点击超链接或者在控制台window.open打开页面B,都是属于当前页面的延续,属于一个会话

在A页面已经打开的前提下,然后在新tab打开同域页面C,此时C和A页面无直接关系,不属于一个会话。

上文中已经说了的,sessionStorage并不是共享的,而是复制的。

B页面打开的时候复制了A页面的sessionStorage,仅仅是复制

此时,无论修改A页面的sessionStorage还是修改B页面的SessionStorage,都不会彼此影响。

也就是说两个页面存储的SessionStorage数据都不会同步变化(各自都是自己的存储,存储独立存在)。