最新版koa+typescript+mysql+pm2搭建部署服务

2,247 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

最近在双十一活动快要结束的时候,薅了一波阿里云的羊毛,买了一台轻量服务器,选择应用镜像WordPress等,稍等几分钟,服务器就初始化ok了。拿到手后直接搞点事情,使用最新版koa,koa-router,typescript,mysql,typeorm,pm2搭建和部署一套后台系统。

Koa基于Node.js平台的下一代web开发框架,加上JavaScript类型的超集TypeScript,配合网站开发时常用的数据库mysql以及pm2,总能快速完成整体构建部署。

初步工程搭建

初始化项目

新建一个文件夹water_service,然后执行如下命令,一路点击回车确认,初始化项目。

npm init

安装项目依赖,这里区分dependenciesdevDependencies依赖,devDependencies依赖安装时加上-D即可,首先安装koa

npm install koa
npm install @types/koa -D

接着安装typescriptts-node,并在package.json文件中scripts添加dev

// package.json
...
"scripts": {
  "dev": "nodemon --watch src -e ts,tsx --exec ts-node src/index.ts",
  "test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
  "koa": "^2.14.1"
},
"devDependencies": {
  "@types/koa": "^2.13.5",
  "nodemon": "^2.0.20",
  "ts-node": "^10.9.1",
  "typescript": "^4.9.4"
}

新建tsconfig.json文件,并设置

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2015", // 目标js版本
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true, 
    "useDefineForClassFields": true, 
    "module": "CommonJS",
    "moduleResolution": "node",
    "outDir": "./dist",
    "esModuleInterop": true, 
    "forceConsistentCasingInFileNames": true,
    "strict": true, 
    "skipLibCheck": true 
  },
   "include": [
    "src/**/*"
  ],
  "exclude": ["node_modules"]
}

编写koa服务器

创建src/index.ts,编写一个koa服务器,代码如下:

import Koa from 'koa';
const app = new Koa();

app.use(async ctx => {
  ctx.body = 'Hello World';
});

app.listen(3000);

执行如下命令,启动服务

npm run dev

访问服务

使用curl访问该服务,如下所示:

curl localhost:3000
Hello World

现在一个简单的koa服务已经通了。

创建路由

安装路由包

使用koa-router及其@types/koa-router,安装

npm install koa-router
npm install @types/koa-router -D

编写路由代码

新建src/controllers/user.ts,编写主要处理代码

import { Context } from 'koa';
export default class UserController {
  public static async listUsers(ctx: Context) {
    ctx.body = 'This is listUsers';
  }
}

然后新建src/routes.ts文件,建立路径映射关系

import Router from 'koa-router'
import UserController from './controllers/user'

const router = new Router()
router.get('/users', UserController.listUsers)

export default router

修改src/index.ts文件,注册路由中间件

...
import router from './routes';

app.use(router.routes()).use(router.allowedMethods());

测试路由

使用postman进行测试,发现没有问题!

image.png 注:路由可以使用jsonwebtoken做JWT鉴权,有兴趣的读者可以添加上。

接入数据库

安装数据库包

安装mysql数据库相关包,mysql reflect-metadata typeorm

npm install mysql reflect-metadata typeorm

新建src/entity/user.ts,创建数据模型定义

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column()
  name!: string;

  @Column({ select: false })
  password!: string;

  @Column()
  email!: string
}

连接数据库

新建数据库配置文件src/db/config.ts,填写数据库ip地址、端口号、用户名、密码等关键信息

import { User } from '../entity/user'
export const mysqlLogin = {
  host: 'ip地址', // 数据库地址
  port: 3306, // 端口
  username: '用户名',
  password: '密码',
  database: "数据库名称",
  entities: [User],
  synchronize: true,
  logging: false
}

修改src/index.ts,初始化连接

...
import { DataSource } from "typeorm"
import { mysqlLogin } from './db/config'

const AppDataSource = new DataSource({ 
  ...mysqlLogin,
  type: 'mysql'
 })
 
 AppDataSource.initialize()
  .then(() => {
    console.log("Data Source has been initialized!")
    app.use(router.routes()).use(router.allowedMethods());
    app.listen(3000)
  })
  .catch((err) => {
    console.error("Error during Data Source initialization", err)
  })
  export { AppDataSource }

修改src/controllers/user.ts,CURD操作数据库

import { AppDataSource } from '../index'
public static async listUsers(ctx: Context) {
  const userRepository = AppDataSource.getRepository(User)
  const users = await userRepository.find();

  ctx.status = 200;
  ctx.body = users;
}

如果是直接连接轻量服务器上的数据库,需要进入阿里云服务器详情页,安全-->防火墙-->添加规则,开放数据库3306端口。以及打开数据库访问权限,登录数据库执行如下语句:

use mysql;
select host from user where user='root'; 
update user set host = '%' where user ='root';
flush privileges;

image.png

image.png

测试数据库

还是访问之前的接口,就能看到返回的结果,对比发现和数据库表中的一致,ok 是成功的!。(由于之前通过接口写入过数据在数据库中,所以此时表中有数据)

image.png

image.png 注:表中的密码已通过加密处理。

部署服务

服务器环境

本文中轻量服务器选择是WordPress应用镜像,上面没有node、pm2等环境,以node为例配置上该环境。 登录服务器后下载node包,然后解压文件,创建软链接。

// 下载node包
wget https://nodejs.org/dist/v14.15.1/node-v14.15.1-linux-x64.tar.xz
// 解压文件
tar xvf node-v14.15.1-linux-x64.tar.xz
// 创建软链接
ln -s ~/node-v14.15.1-linux-x64/bin/node /usr/local/bin
ln -s ~/node-v14.15.1-linux-x64/bin/npm /usr/local/bin

因node包中含有npm,就直接一次性安装了,然后查看对应版本信息,其他环境读者自行使用类似方法安装。 image.png

打包项目

项目采用的是typescript编写,需要先编译成node能识别的js文件,可编译成es2015,查看上文给出的tsconfig.json文件并配置如下命令:

// package.json
"scripts": {
  ...
  "build": "rm -rf dist && tsc"
}

执行构建build命令,完成后会发现项目根目录下有打包好的文件夹dist

npm run build

上传到服务器

本地通过scp命令,把代码上传到轻量服务器上,比如上传到/data/wwwroot/service,当然也可以打个tar包压缩下再上传

scp -r dist package.json 用户名@服务器ip:/data/wwwroot/service

启动服务

启动服务前先下载必要依赖包,只需要下载package.json中dependencies包含的包就行

npm install --production --unsafe-perm=true --allow-root

使用pm2启动服务

pm2 start dist/index.ja

还是在轻量服务器详情页面打开服务器网关3000端口(与服务端口对应),允许外部访问。

测试服务

使用postman访问服务接口,访问没问题!

image.png 至此,这篇文章写完了。其实在实际操作中还是踩了一些坑,如果觉得写得还行,记得点赞+关注+评论哦!