nodejs+express 入门


如果你正在搭建自己的 Web 服务、后端接口或 AI 应用,那么 Express 绝对是 Node.js 生态里最值得上手的框架。它轻量、高效、扩展性强,从构建路由、管理中间件,到连接 MySQL、部署生产环境,都能做到简单易用。本文将手把手带你完成:使用 Express 搭建服务器、配置模板引擎、编写接口、连接数据库、使用 nodemon 热更新、调用 ChatGPT API(laf 实现),并最终部署到服务器。通过本指南,你可以快速构建属于自己的完整后端服务,实现从开发到上线的全流程。

一、 express

express是一个轻量级的node.js web应用程序开发框架,为web和移动应用程序提供一组强大的功能,可以帮助我们快速搭建基于nodejs的web应用。通俗来说:express可以搭建服务器,接受前端发送过来的请求,并连接数据库,通过一系列操作做出响应发送到前端。

JavaScript
// 安装express脚手架
npm install express express-generator -g

express --version   //4.16.1

express --view=pug/ejs // 创建express项目,pug或ejs模板引擎
  1. 生成项目文件结构:
JavaScript
 .
 ├── app.js
 ├── bin
 │   └── www  // 启动文件
 ├── package.json
 ├── public // 静态资源、公共js代码 可以放这里
 │   ├── images
 │   ├── javascripts
 │   └── stylesheets
 │       └── style.css
 ├── routes // 项目的路由,也就是前端请求的接口
 │   ├── index.js  // 根路由
 │   └── users.js
 └── views // 服务端渲染页面,
     ├── error.pug  // pug/jade --模板引擎,用于生成 HTML
     ├── index.pug
     └── layout.pug
  • 模板渲染引擎:express 提供了一系列模板引擎,比如 pug,mustache,ejs 等等,目前使用pug作为默认的模板引擎(jade改名而来)

使用模板引擎需要配置:

JavaScript
// 配置模板的位置, 通常在项目views文件夹下
app.set('views',path.join(__dirname, 'views'))

//配置使用的模板引擎
app.set('view engine','ejs')

npm i ejs
  • pug基本用法:
  • 基本路由: 用来向特定的客户端请求返回对应数据。
JavaScript
 app.METHOD(PATH, HANDLER)
 // app: express的一个实例
 // METHOD:一个 http 请求,用小写(lowercase)
 // PATH: 服务端路径
 // HANDLER: 处理函数
  • 静态文件: 直接通过路由来访问,使用express提供的中间件实现:
JavaScript
// 通过 express.static() 方法可创建静态资源服务器,向外开放访问静态资源
express.static(root,[option])

提供给 express.static 的路径需要和目录相关联的 :

JavaScript
const path = require('path')
app.use(express.static(path.join(__dirname, 'public')))

// 通过带有 /test 前缀的地址访问 public目录下的文件
app.use('/test', express.static('public'))

当托管多个静态资源时,访问静态资源时,会根据托管顺序查找文件.

  • 中间件
    • 全局中间件:客户端发起的任何请求,到达服务器之后,都会触发的中间件,通过app.use()定义的中间件为全局中间件
    • 局部中间件:不使用app.use()定义的中间件
    • 应用级别的中间件: 通过 app.use()app.get()app.post(),绑定到app实列上的中间件
    • 路由级别的中间件:绑定到 express.Router() 实例上的中间件
    • 错误级别中间件:用来捕获整个项目中的异常错误,处理函数必须4个形参: (err, req, res, next)
      • 错误级别的中间件必须注册在所有路由之后(一般的中间件都是需要在注册路由之前的)
    • Express 内置中间件(express 4.16.0+)
      • express.static: 快速托管静态资源,见上文
      • express.json: 解析 JSON 格式的请求体数据
      • express.urlencoded: 解析 URL-encoded 格式的请求体数据
    • 自定义中间件

二、 连接mysql

本地安装mysql数据库或连接云数据库

JavaScript
const mysql = require('mysql')

const db = mysql.createPool({
  host: "127.0.0.1",
  user: "root",
  password: 'xd123456',
  database: 'sqltest',
})

db.query("select 1", (err, results) => {
  if (err) {
    return console.log(err)
  }
  console.log(results)
})

module.exports = db
JavaScript

//增
app.get("/increase", (req,res)=>{
  // 先取到要增加的字段值
  const addInfor = req.query
  // 定义sql语句
  const sql = "insert into list set ?"
  // 执行sql语句,第二个参数代表sql语句中?的值
   db.query(sql, addInfor, (err,results)=>{
    // sql语句执行失败
    if(err) {
      return res.send({status: 1, message: err.message})
    }
    // 数据库语句执行成功,但影响的条数不等于1,没有增加,也属于失败
    if(results.affectedRows !== 1) {
      return res.send({status: 1, message: '数据添加失败'})
    }
    // sql语句执行成功,影响条数也等于1
    return res.send({status:0, message: '添加成功', data:results})
  })
})


// 查
app.get("/info", (req, res) => {
  // 定义sql语句:意思为查询test表
  const sql = "select * from list";
  // 执行sql语句
  db.query(sql, (err, result) => {
    // 执行失败
    if (err) {
      return res.send({ state: 1, message: err });
    }
    //执行成功后返回,表中的数据
    return res.send({ state: 0, message: "查询成功", data: result });
  });
});

三、小工具 nodemon

使用 node ./bin/www 运行项目不能进行热更新,修改代码后,需要重复执行node ./bin/www

使用 nodemon 持续运行,便于调试:

JavaScript
npm install nodemon -g
// 修改 package.json:
"scripts": {
    "start": "node ./bin/www"
    "start": "nodemon ./bin/www"
  },

四、 连接chatGPT(laf实现)

JavaScript
import cloud from '@lafjs/cloud'

export default async function (ctx: FunctionContext) {
  const { ChatGPTAPI } = await import('chatgpt')
  const { body, response } = ctx

  // 这里需要把 api 对象放入 cloud.shared 不然无法追踪上下文
  let api = cloud.shared.get('api')
  if (!api) {
    api = new ChatGPTAPI({ apiKey: cloud.env.CHATGPT_API_KEY })
    cloud.shared.set('api', api)
  }

  // set stream response type
  response.setHeader('Content-Type', 'application/octet-stream');

  // send message
  const res = await api.sendMessage(body.message, {
    onProgress: (partialResponse) => {
      if (partialResponse?.delta != undefined)
        response.write(partialResponse.delta)
    },
    // 如果前端传入parentMessageId,则需要追踪上下文
    parentMessageId: body.parentMessageId || ''
  })

  response.end("--!" + res.id)
}

五、服务器部署

Bash
// 安装node环境
sudo apt-get update
sudo apt-get install nodejs

node -v

sudo apt-get install npm
// 启动应用程序
node app.js
// 或使用全局安装的PM2自动管理进程
pm2 start app.js

// 使用nginx作为反向代理
sudo apt-get install nginx

sudo nano /etc/nginx/sites-available/myapp

添加配置:

Apache
server {
    listen: 80;
    server_name domain.com;
    
    // 如果启用https协议, 在购买ssl证书后加入配置:
    ssl on;
    ssl_certificate /path/to/your_cert.pem;
    ssl_certificate_key /path/to/your_key.pem;
    
    location / {
       proxy_pass http://localhost:3000;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
    }
}

参考文档:

  • https://www.expressjs.com.cn/
  • https://expressjs.com/en/starter/examples.html
  • https://www.npmjs.com/package/chatgpt
  • https://icloudnative.io/posts/build-chatgpt-web-using-laf/