nodejs web框架开发express(一)

express 介绍

  • express 是 nodejs 的一个web开发框架,支持 mvc 模式,路由,数据库连接,网页渲染,过程处理集一身的框架
  • 官方网站

快速入门

  • 安装环境
    1. nodejs
    2. npm install -D express
  • Hello world程序
// app.js
const express = require('express')
const app = express()

app.get("/", (req, res) => {
	res.json("Hello World")
})

const port = 8999;
app.listen(port, () => {
	console.log(`server running on http://localhost:${port}`)
})

常用组件

  • 开发推荐
// 使用nodemon 启动,可以更改后自动更新,不用重启
npm install -g nodemon
// 在 package.json 中, 添加 scripts
{
  "devDependencies": {
    "express": "^4.18.2"
  },
  "scripts": {
    "dev": "nodemon runserver.js"
  }
}
// 启动服务
npm run dev
  • 开启 json 解析,否则 req.body 为空
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded

1. 项目设置

  • Router
// 1. 路由限制大小写 caseSensitive 默认 false
var router = express.Router({caseSensitive:  true})
// 2. 最后斜杠严格限制 strict 默认 false
var router = express.Router({strict: true})
router.get("/Foo", (req, res) => {
    res.json("Foo1")
})

router.get("/foo", (req, res) => {
    res.json("foo2")
})

app.use('/', router);
  • 结果如下
C:\Users\Rao>curl 127.0.0.1:8999/foo/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /foo/</pre>
</body>
</html>

C:\Users\Rao>curl 127.0.0.1:8999/foo
"foo2"
C:\Users\Rao>curl 127.0.0.1:8999/Foo
"Foo1"
C:\Users\Rao>
  • 另外,参数默认普遍有 100kb 的大小限制,具体可根据 官网express进行修改

  • 端口和监听地址

app.listen(3999)
app.listen(3999, "127.0.0.1")
app.listen(3999, "0.0.0.0")
// 设置服务启动后,打印信息
const port = 8999;
const hostname = "localhost";
app.listen(port, "0.0.0.0", () => {
    console.log(`server running on http://${hostname}:${port}`)
})
  • 全局设置
// 设置限制大小写,false 为 忽略大小写
app.set("case sensitive routing", true)
app.get("/Goo", (req, res) => {
    res.json("Goo")
})

app.get("/goo", (req, res) => {
    res.json("goo")
})
属性类型说明默认值
case sensitive routingBoolean开启限制大小写关闭忽略大小写false
envString环境变量默认为系统变量 NODE_ENV
etagVariedSEO优化项目,URLTag,可选 true,false, weak, strongweak
jsonp callback nameStringjsonp回调名“callback”
json escapeBooleanjson转义,防止xss攻击N/A (undefined)
json replacerVaried添加空格和回车,美化json数据展示, stringify 参数 replacerN/A (undefined)
json spacesVaried添加空格和回车,美化json数据展示, stringify 参数 spacesN/A (undefined)
query parserVaried自定义query请求解析“extended”
strict routingBoolean设置为true, /foo 和 /foo/ 将是两个不同的请求N/A (undefined)
subdomain offsetNumber使用域名时,子域名与父域名之间不能超过2个.2
trust proxyVaried代理设置,详情请看官网false (disabled)
viewsString or Array服务默认查找的html模板目录,如果是数组,将按照顺序查找process.cwd() + ‘/views’
view cacheBoolean开启html静态文件缓存true in production, otherwise undefined.
view engineStringview 渲染引擎,可选 html, jade, 需要安装额外插件N/A (undefined)
x-powered-byBoolean开启后将在头部添加 “X-Powered-By: Express”true
  • mountpath 挂载路径 (实现子组件添加到项目中)
var admin = express()

admin.get('/', function (req, res) {
  // 显示目录的父目录挂载目录,感觉没啥用
  console.dir(admin.mountpath) // [ '/adm*n', '/manager' ]
  res.send('Admin Homepage')
})

var secret = express()
secret.get('/', function (req, res) {
  console.log(secret.mountpath) // /secr*t
  res.send('Admin Secret')
})

admin.use('/secr*t', secret) // load the 'secret' router on '/secr*t', on the 'admin' sub app
app.use(['/adm*n', '/manager'], admin) // load the 'admin' router on '/adm*n' and '/manager', on the parent app

2. 路由组件

  • 路由分层
  1. app 路由
  2. 子组件 路由
  3. route组件路由
    1. app 路由,直接使用 app.get app.post
app.get("/Goo", (req, res) => {
    res.json("Goo")
})
    1. 子组件路由,使用 另一个 express 服务,挂在在路由上
// 请注意,该方式下,有些全局参数不能生效,具体查看[官网](http://expressjs.com/en/4x/api.html#app.set)
const app = express()

const app2 = express();

app2.get("/", (req, res) => {
    res.send("This is sub-app server")
})

app.use("/app2", app2)
  1. 使用router 挂载在 app 上,该方式可以嵌套
var router = express.Router({caseSensitive: true, strict: true})

var router2 = express.Router();
router.get("/Foo", (req, res) => {
    res.json("Foo1")
})

router2.get("/run", (req, res) => {
    res.send("run")
})

router.use("/router2", router2)
app.use('/', router);
// 访问 http://localhost:8999/router2/run

3. req 对象

  • request 对象,包含请求头,cookies ,请求体,等http 信息, 具体请参看下表
对象返回值说明
req.app整体服务的一些变量具体打印查看
req.baseUrl上一层路由地址
req.bodyform-data 或者 json 格式内容
req.cookiescookies
req.fresh缓存是否打开
req.hostnamehostname,在app设置的那个变量
req.ip服务器ip
req.ips代理开启时,代理地址数组
req.method请求方法
req.originalUrl和url差别,显示完整url,包括父组件或者父路由
req.params路由请求参数不是?userid=1 而是 /users/1/ 这里的参数
req.pathurl包含query参数,path不包括
req.protocolhttp or https
req.query?user=1 请求参数
req.resresponse对象
req.routeRoute对象
req.securehttps 与否
req.signedCookies登录用户组件
req.stalereq.refresh反义词
req.subdomains域名解析的子域名数组
req.xhrxhr 请求支持
Methods
req.accepts()判断请求头
req.acceptsCharsets()判断请求头
req.acceptsEncodings()判断请求头
req.acceptsLanguages()判断请求头
req.get()获取请求头数据
req.is()判断请求头
req.param()万能获取参数方式
req.range()限制请求头大小解析

4. res 对象

  • 官网链接
  • 只选重要的写
  • 返回方式
    1. json
    2. text
    3. 文件
    4. 网页渲染
  • 额外信息附加
    • 更改请求头(包含cookies)
    • 更改状态码

1. json 格式

  1. res.json({"name": "1"})

2. text 格式

  1. res.send("content")

3. 文件 (传入文件名)

  1. res.download()
  2. res.attachment()
  3. res.sendFile()

4. 网页渲染

res.render('index', function (err, html) {
  res.send(html)
})

5. 添加请求头,添加cookies

res.append('Link', ['<http://localhost/>', '<http://localhost:3000/>'])
res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly')
res.append('Warning', '199 Miscellaneous warning')
  • cookies
res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true })
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true })

6. 修改状态码

res.status(403).end()
res.status(400).send('Bad Request')

5. 中间层 middleware(待写。。。)

  • 待写。。。。
  1. 用户登录
  2. 权限管理
  3. 日志记录

6. 数据库操作

1. mysql连接

  • 支持多种关系型数据库(sqlite3,mysql,postgresql,SQLServer,DB2)
  • 本次演示以 sqllite3 为例,该数据库为文件数据库,不需要预先安装数据库
  1. 安装npm依赖
    • npm i sequelize
    • npm i sqlite3

2. 创建数据库连接

const sequelize = new Sequelize('test', '', '',{
    dialect: 'mysql',
    hostname: '127.0.0.1',
    port: 3306,
    database: "test"
});

try {
    sequelize.authenticate().then(r => {
        console.log('Connection has been established successfully.');
    }).catch (err => {
        console.error('Unable to connect to the database:', err);
    });
} catch (error) {
    console.error('Unable to connect to the database:', error);
}

3. mysql 定义对象 ORM

const Student = sequelize.define('User', {
    // 在这里定义模型属性
    firstName: {
        type: DataTypes.STRING,
        allowNull: false,
        defaultValue: "zhangsan",
    },
    gender: {
        type: DataTypes.STRING
        // allowNull 默认为 true
    },
    id: {
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
    }
}, {
    // 这是其他模型参数
});

const Score = sequelize.define('Score', {
    // 在这里定义模型属性
    score: {
        type: DataTypes.INTEGER,
        allowNull: false
    },
    name: {
        type: DataTypes.STRING,
        allowNull: false,
    },
    student: {
        type: DataTypes.INTEGER,
        // allowNull 默认为 true
        references: {
            model: Student,
            key: 'id',
        }
    },
    id: {
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
    }
}, {
    // 这是其他模型参数
});
Student.hasMany(Score, {
    foreignKey: 'student'
});

4. mysql 操作

1. sql 操作

	- `sequelize.query("sql_str")`

2. ORM 操作

  1. 同步模型到数据库
// sequelize.sync 函数执行
const sequelize = require("./db");
const {Student, Score} = require("./student")

async function syncDB() {
    await sequelize.drop();
    sequelize.sync({ force: true }).then( (r) => {
        console.log("同步完成")
        Student.create({"firstName": "123", "gender": "male"})
    }).catch(error => {
        console.error("同步失败 ", error)
    })
    console.log(await sequelize.query("show tables;"))
    // CREATE TABLE IF NOT EXISTS `Users` (`firstName` VARCHAR(255) NOT NULL DEFAULT 'zhangsan', `
    // gender` VARCHAR(255), `id` INTEGER PRIMARY KEY AUTOINCREMENT, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIM
    // E NOT NULL);
}

module.exports = {syncDB}

  1. 写入,查询
const express = require("express");
const {Score} = require("../models/student");
const {Student} = require("../models/student");

const StudentRouter = express.Router();


StudentRouter.get("/", async (req, res) => {
    const student = await Student.create({"firstName": "1111", "gender": "None"})
    const score = await Score.bulkCreate([{"score": 100, "name": "math"}, {"score": 90, "name": "language"}, {"score":  59, "name": "physics"}])
    await student.addScore(score);
    res.send("student add success")
})


StudentRouter.get("/show", async (req, res) => {
    let studentData = await Student.findByPk(2, {include: [Score]});
    res.json(studentData)
})

module.exports = {StudentRouter}

7. restful API设计 (待写。。。。)

  • 待写。。。。

从一个学生管理系统开始 (待写。。。。)

  • 学习目标
- 掌握数据库概念化定义ORM 
- 掌握复杂路由设置
- 掌握常用插件使用

1. 学生管理系统设计

  • 学生信息展示
  • 学生登录
  • 学生考试成绩

2. 数据库定义

  • 学生表

参考

  1. 数据库处理
    • https://www.bookstack.cn/read/sequelize-5.x-zh/spilt.2.getting-started.md
    • https://www.cnblogs.com/alexander3714/p/14158395.html
    • https://www.sequelize.cn/advanced-association-concepts/eager-loading
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值