一文搞清 Strapi5 的安装与使用 | 踩坑爽 (bushi
本文最后更新于:2025年1月20日 晚上
我的 Strapi 版本:v5.0.0
节点版本:v20.13.1
数据库:MySQL8
数据库 受到推崇的 最低限度 MySQL 8.0 8.0 玛丽亚数据库 10.6 10.5 PostgreSQL 14.0 12.0 SQLite 3 3 Strapi 官方文档地址:https://strapi.nodejs.cn/dev-docs/installation/cli
一文搞清 Strapi5 的安装与使用 | 踩坑爽 (bushi
前言
本篇文章主要是从安装到使用,说说我在 Windows | WindowsServer 上使用 Strapi5 作后端数据服务器时碰到的一切坑。
安装 Strapi
检查本地环境
请转到 Strapi 官方文档,对照官方文档要求检查你本地的 Node.js
和 npm
版本。我的环境如下:
Node.js 版本:
npm 包管理器版本
官方文档中使用 Python 是为了支持它默认的 SQLite 数据库,我这里使用的是 PHPStudy 集成的 MySQL8, 数据库,所以 Python 环境是不必须的。
✋ 提醒
Strapi 不支持 MongoDB。
安装 yarn(可选)
我之后投入了 yarn 的怀抱,所以这里可以安装一下 yarn 作为包管理器,非必须!
卸载命令是
我的 yarn 版本是
创建 Strapi 项目
在一个你准备好的目录中,使用终端 cmd
或 powershell
执行
✋ 注意
Yarn does not support passing the version tag such as
@latest
, as opposed to npm. If you experience unexpected results with yarn and the latest version of Strapi is not installed, you might need to run theyarn cache clean
command to clean your Yarn cache.Yarn 不支持传递版本标签,如
@latest
, 这与 npm 相反。如果您在使用 yarn 时遇到意外结果,没有安装最新版本的 Strapi,您可能需要运行 [yarn cache clean](https://yarn . nodejs . cn/CLI/cache/clean) 命令来清理 Yarn 缓存。
或者使用 npm
我推荐创建时,使用 npm 以保证安装最新版本的 Strapi
以下是我的安装选择:
? Please log in or sign up. Skip
:意思是让你进行在线登录,我选择跳过? Do you want to use the default database (sqlite) ? (Y/n) n
:是否使用默认的 sqlite 数据库,我选择否? Choose your default database client mysql
:出现三个选项让你选择,我选择 mysql? Database name: demo1
:输入要连接的数据库名字(准备好一个空表的数据库)? Host: localhost
:数据库的 host 地址,本地就是 localhost,远程填公网 ip? Port: 3306
:数据库端口,我选择默认端口 3306? Enable SSL connection: (y/N) N
:是否启用 SSL 连接?可自行决定(什么是数据库 SSL 连接?)? Start with an example structure & data? (y/N) N
:是否需要安装时附带简单数据?我自行决定数据,所以选否? Start with Typescript? (Y/n) n
:项目需要 TypeScript 吗?可自行决定? Install dependencies with npm? (Y/n) Y
:是否使用 npm 安装依赖?我选择是,省去手动安装依赖的命令? Initialize a git repository? (Y/n) n
:是否初始化一个 git 仓库?可自行决定
经过些许等待,看到以下画面说明成功了:
如果你在安装时选择了不自动安装依赖,进入项目内是没有 node-modules 包的,可手动安装
安装好依赖之后请先别着急启动,接着看汉化步骤(如果你英语好,也请看看汉化小节的最后,运行命令在那里)
Strapi 汉化
项目运行登录进面板之后点击左下角的 profile 进行设置
运行 Strapi 应用
或
Strapi 运行 - MySQL 建表报错
Error: alter table
i18n_locale
add indexi18n_locale_documents_idx
(document_id
,locale
,published_at
)
Specified key was too long; max key length is 1000 bytes
类似上述报错,这是因为 MySQL 对于 InnoDB 存储引擎有一个索引键长度的限制,这个限制基于字符集的不同而不同。在使用 utf8
字符集时,每个字符可能占用 3
个字节,那么对于 innodb
表,索引键的最大长度大约为 1000
个字符左右(因为 3072 / 3 ≈ 1024
)。若字符集是 utf8mb4
,每个字符可能占用 4
个字节,所以最大长度会进一步减少到 768
个字符左右(3072 / 4 = 768
)
uf8mb4 字符集:
要在 Mysql 中保存 4 字节长度的 UTF-8 字符,需要使用 utf8mb4 字符集(mb4 就是 most bytes 4 的意思,专门用来兼容四字节的 unicode),但只有 5.5.3 版本以后的才支持。
为了获取更好的兼容性,应该总是使用 utf8mb4 而非 utf8. 对于 CHAR 类型数据,utf8mb4 会多消耗一些空间,根据 Mysql 官方建议,使用 VARCHAR 替代 CHAR。其实,utf8mb4 是 utf8 的超集,理论上原来使用 utf8,然后将字符集修改为 utf8mb4,也会不会对已有的 utf8 编码读取产生任何问题。当然,为了节省空间一般情况下使用 utf8 也就够了。
解决办法
由于我使用的是 PHPstudy 集成的 MySQL8 所以直接找到 PHPstudy 将引擎改为 InnoDB 就好了
Strapi 启动项目登录凭证
正确启动之后,会自动打开浏览器访问 admin 管理面板的注册页面,请自行注册。
注册产生的凭证决定你是否能登录上 Strapi 的管理面板,请妥善保存你的登录信息。
可只保存关键信息,下面是我的示例:
配置项 | 值 |
---|---|
name | 4rozen |
姓氏 | Chen |
电子邮件 | maril4chen@foxmail.com |
密码 | Strapi1005 |
了解 Strapi 的身份管理机制
Strapi 可以设置普通注册用户为 Authenticaed 或 public 分组
由于进行普通注册会默认得到 jwt 令牌,所以我们可以设置为 Authenticaed 分组
这里你一定会疑惑 Strapi 的身份机制到底是什么?
对普通用户简单来说有以下身份:
- public:未经过身份验证的用户所在分组,访问接口只能访问公共接口
- Authenticaed:经过身份验证的用户所在分组,访问接口更多
身份验证发生在登录或者是注册,能完成其中之一都可以算作身份验证通过
每一个用户登录之前都是 public 用户,在注册后就成为了 Authenticaed user 经过验证的用户。
Strapi 使用 Roles 来对普通注册的 user 用户进行分组,在 content manager 中有默认创建的 Users 表,可以点击用户进行设置,分为以下身份:
Authenticaed:身份验证通过的用户
public:路人
Strapi 同样也对通过后台 admin 进行注册的管理员用户使用 Roles 来进行管理,分为:
- Author:作者可以管理他们创建的内容。
- Editor:编辑者可以管理和发布内容,包括其他用户的内容。
- Super Admin:超级用户可以访问和管理所有功能和设置。
第一次注册进来默认是 Super Admin 超级管理员。
如果有更多人,点击 Administration panel 管理面板中的 Roles 角色可以进行分组管理。
如何创建表结构
可能看到上面的身份管理你一脸懵,没关系,我们先来创建一个用于存放商品信息的示例表:
点击左侧侧边栏的 Content-Type Builder 内容构建
点击 Create new collection type 创建内容集合类型的复杂数据表,这种表结构支持表与表之间的引用关联,这有助于我们创建符合数据要求的数据结构
填写单数形式的表名,当然复数形式的表名也可以
点击 ADVANCED SETTINGS 高级设置
点击 Continue 继续,此时需要你进行表的字段设置,比如设置商品名和商品图如下:
具体设置 Text 类型的商品名如下:
设置商品图片如下:
添加成功之后别忘记点击 Save 保存
之后 Strapi 将进行重启,不出意外将成功创建 Good 数据表和我们刚才添加的字段:
填充数据:点击左侧边栏的 Content Manager 内容管理选择刚才我们创建的数据表 good 并点击右上角的 Create new entry 创建实体就行了。
Strapi 接口权限设置
数据表有了,怎么通过接口调试呢?
Strapi 的接口要想调试,首先得给予权限。
找到左侧侧边栏的 setting 然后点击 Roles
Authenticated
为经过注册等身份验证手段的用户,而 Public 为公共用户。这将以此分割接口权限,Public
为随便就能访问的接口,Authenticated
为身份验证之后才能使用的接口除了登录注册接口,我们可能会希望所有接口能够经过权限验证才能通行。但是我这里为了演示,就将
good
表的接口给Public
用户开通:别忘记右上角点击保存。我这里直接使用浏览器进行接口测试:
如果想接口限权,只允许身份验证的用户才能使用的话,就请给 Authenticated
用户开权限而不是 Public
Strapi 接口文档查看
说到接口,这里推荐安装 document 插件进行可视化查看,因为 Strapi 默认不提供可视化的接口文档,只提供接口路由可供查看。
插件官方文档:https://docs.strapi.io/dev-docs/plugins/documentation
安装接口文档插件命令
接口文档访问地址
其中 Users-Permissions - Auth 为认证用户和普通用户的接口,下面的 User-Permissions 则是管理员端的相关接口。
配置邮箱发信插件
Strapi 默认并不会自行配置邮件服务。
为了能够发送邮件(例如密码重置邮件),需要设置一个邮件提供商(如 SendGrid、Gmail、SMTP 等)。如果没有配置邮件提供商,本地 Strapi 无法实际发送邮件。
安装 nodemailer
插件
配置 Email Provider
接下来,需要配置邮件提供商。
在 Strapi 中,邮件服务的配置文件位于 config/plugins.js
。国内推荐 qq 或者网易邮箱(自行搜索邮箱开通 SMTP),这里介绍网易邮箱配置:
获取 SMTP 授权码
- 登录 163 邮箱。
- 打开 设置 -> POP3/SMTP/IMAP。
- 开启 SMTP 服务,并生成授权码(授权码只展示一次,请妥善保存)。
在你的 .env
文件中设置相应的环境变量
修改 template 模板
将模板中的发件人和刚才配置的插件文件中的发件人一致
否则你可能遇到错误
API - 查询媒体数据
在查询某些包含关系、媒体字段(图片、视频等)、组件或动态区域的接口时,如果不在查询参数中加上 populate
参数,Strapi 将默认不会查询返回,这是出于性能考虑。
例如 /api/users/me
接口,假设 Users 表中还包含一个 avatar 头像字段,则想要接口返回头像数据,应该是如下查询(*
表示查询所有关系)
populate 参数中文文档参考:https://strapi.nodejs.cn/dev-docs/api/rest/populate-select/
API - 查询特定字段
查询请求可以接受 fields
参数来仅选择某些字段。默认情况下,仅返回以下 字段类型:
- 字符串类型:字符串、文本、富文本、枚举、电子邮件、密码和 uid,
- 日期类型:日期、时间、日期时间和时间戳,
- 号码类型:整数、大整数、浮点数和小数,
- 通用类型:布尔值、数组和 JSON。
字段选择不适用于关系、媒体、组件或动态区域字段。要填充这些字段,请使用
populate
参数。
该参数可以限制响应的数据字段,可以使得某些数据不被暴露,一定程度提高安全性和数据简洁性。
例如 /api/users/me
接口,查询所有的关系返回数据为
如果带上下面的请求参数
则返回数据为
参数解释
fields
关键字表示要进行第一级的字段选取,populate[第一个参数][第二个参数]
的第一个中括号参数为第二级字段的根节点(这里是 avatar
),接着第二个中括号写 fields
关键字,表示要进行选取的字段名,这里是 id,height,width,name,updatedAt,ext
API - 文件上传
Strapi 的文件上传除了在管理面板中进行上传之外,还可以通过接口的方式进行上传(Strapi 支持 blob、base64 上传,请提前给予权限)
请在接口前加上 /api,即:
例如在 apifox 中进行测试:
API - 更新包含媒体字段的数据
那么如果我创建了一个数据表其中包含一个媒体字段,如何更新该表中的数据?
假设该表如下:
请求接口为:
访问接口文档插件的地址,你会发现它的示例如下:
"cover_img": "string or id"
string 或者 id?string 说是网络地址我都能理解,id 是什么?
- 实际上该接口仅仅允许你通过已经上传的图片 id 进行设置 cover_img
也就是说你要先将更换好的图片进行上传,然后得到它的 id,再将该 id 赋值给 cover_img 才行
折腾了我一晚上,各种曲线救国写的累死人,没想到随意一个测试,原来是这样的…… 哈哈😎😎
API-Strapi 条件查询
Strapi 如何进行条件查询?
参考文档:
总之,Strapi 提供了一些常见的查询操作符,我们可以通过这些操作符进行各种条件查询。常用操作符包括:
操作符 | 含义 | 示例 |
---|---|---|
$eq | 等于 | filters[title][$eq]=Vue.js Tutorial |
$ne | 不等于 | filters[title][$ne]=Vue.js Tutorial |
$lt | 小于 | filters[views][$lt]=1000 |
$lte | 小于等于 | filters[views][$lte]=1000 |
$gt | 大于 | filters[views][$gt]=1000 |
$gte | 大于等于 | filters[views][$gte]=1000 |
$contains | 包含(字符串部分匹配) | filters[title][$contains]=Vue |
$startsWith | 以指定字符串开头 | filters[title][$startsWith]=Vue |
$endsWith | 以指定字符串结尾 | filters[title][$endsWith]=Tutorial |
$null | 字段值为空 | filters[coverImage][$null]=true |
$in | 在给定数组中 | filters[category][$in][0]=News |
$between | 在两个值之间 | filters[views][$between][0]=10&filters[views][$between][1]=100 |
示例
查询 views
字段在 100 和 1000 之间的文章:
查询 category
是 "Tech" 或 "News" 的文章:
假设数据如下(接口是:/api/articles)
根据分类 id 和文章发布状态进行查询
怎么根据分类 id 和文章发布状态进行查询?比如我要查询文章所属分类为随想且发布状态为已发布
分页查询
通过 pagination
参数在请求中实现分页查询。Strapi 的分页功能包括 page
(页码)和 pageSize
(每页显示的记录数),我们可以在 API 请求的 URL 中传递这些参数。例如:
查询第 2 页的数据,并且每页显示 5 条文章,URL 可以写成这样
分页查询的结果中,Strapi 会在 meta
字段中返回有关分页的信息:
模糊查询
Strapi 支持通过 API 进行模糊查询,我们可以使用 filters
参数结合 $contains
运算符来实现模糊查询。例如:
根据文章标题(title
字段)进行模糊查询,查询包含某个关键词的文章列表,API 请求可以这样写:
我们甚至可以结合分页查询和模糊查询
排序查询
Strapi 支持通过 API 查询时对数据进行排序。我们可以使用 sort
参数来指定排序字段和顺序。
单字段排序查询
单字段排序查询例如:
根据 updatedAt
字段进行排序,可以按照如下方式查询最新更新的文章
sort=updatedAt:desc
:按照 updatedAt
字段降序排列(最新的文章在前)
desc
:降序排列,从新到旧。asc
:升序排列,从旧到新。
多字段排序
例如,首先按 state
(状态),然后按 updatedAt
:
这将先按 state
升序排列,再按 updatedAt
降序排列。
结合分页和过滤
甚至可以将排序与分页、过滤结合使用。例如,查询标题中包含 test
的文章,按 updatedAt
从新到旧排序,并分页显示:
这会返回包含 test
关键词的文章,按更新时间降序排列,并分页显示。
小结
总之,Strapi 提供了多个过滤操作符,使得我们可以灵活地查询数据
$eq
:精确匹配$ne
:不等于$lt
:小于$lte
:小于或等于$gt
:大于$gte
:大于或等于$contains
:包含(模糊查询)$notContains
:不包含$startsWith
:以指定字符串开头$endsWith
:以指定字符串结尾
结语
目前我碰到的问题基本就是这些,如果有更复杂的项目时,可能才会碰到更多问题……
关于 Nginx 如何监听 Strapi 可以看看我的 Vue 打包那篇文章:解决打包后的刷新 404 问题 ->Github Pages 上的 history 路由模式的可行性 -> 一个可能需要的配置参考
我不得不说的是,Strapi 对于表与表之间的引用在 API 接口调试方面体验确实很糟糕,某些接口使用 documentId
有些接口却只认真实 id
不过免费的可用,还能要求什么呢 (〃 ̄︶ ̄) 人 ( ̄︶ ̄〃)