node.js进行web开发

引: 一起来学node.js

目录

1. 安装mangodb数据库

2.  know more 

3.   npm安装模块是不会写入package.json中

4.   设置路由,渲染模板

5. 中间件与next

6. node创建一个博客:包含登录、注册、发表文章等功能


利用node.js实现一个包括路由控制,页面模板,数据库访问,用户注册,登录,会话功能的系统。

1. 安装mangodb数据库

  • key1:创建数据库文件存放位置:D:\db\data\db
  • key2:启动服务:进入\bin文件运行 mongod --dbpath D:\db\data\db

浏览器键入:http://localhost:27017 则可。配置本地服务 :环境变量中添加数据位置。

启动数据库:

mongod --dbpath "D:\db\data\db"

启动项目:

npm start

2.  know more 

  • http模块:能够实现POST请求,以及Cookie、会话的管理。
  • express框架:Web开发框架。

安装:

$ npm i -g express         //安装express
$ npm install -g express-generator  //安装命令工具
$ express --v      //检查版本

项目优点:

  • MVC的设计模式,实现业务逻辑,数据操作视图的分离。

介绍基本内容:

  1. require  可同步加载 .js、.json 和 .node 后缀的文件
  • 如果目录下有 package.json 并指定了 main 字段,则用之
  • 如果不存在 package.json,则依次尝试加载目录下的 index.js 和 index.node

     2. exports 和 module.exports 用来导出代码

  • module.exports 初始值为一个空对象 {}
  • exports 是指向的 module.exports 的引用
  • require() 返回的是 module.exports 而不是 exports

由于模块导出的时候,真正导出的执行是module.exports,而不是exports,所以经常看到这类写法:

exports = module.exports = {...}

原理很简单:module.exports 指向新的对象时,exports 断开了与 module.exports 的引用,那么通过 exports = module.exports 让 exports 重新指向 module.exports。

3.   npm安装模块是不会写入package.json中

第三种方式用于固定版本号,适合线上Node.js 版本:

npm i express --save/npm i express -S (安装 express,同时将 "express": "^4.14.0" 写入 dependencies )
npm i express --save-dev/npm i express -D (安装 express,同时将 "express": "^4.14.0" 写入 devDependencies )
npm i express --save --save-exact (安装 express,同时将 "express": "4.14.0" 写入 dependencies )

4.   设置路由,渲染模板

index.js

const express = require('express')
const app = express()
const indexRouter = require('./routes/index')

app.use('/', indexRouter)

app.listen(3000)

      生成一个 express(web框架) 实例 app,挂载了一个根路由控制器,然后监听 3000 端口并启动程序。  

routes/index.js

const express = require('express')
const router = express.Router()

router.get('/', function (req, res) {
  res.send('hello, express')
})

module.exports = router

    将 /   的路由放到了 routes/index.js 。路由文件通过生成一个 express.Router 实例 router 并导出,通过 app.use 挂载到不同的路径。

index.js  : 模板引擎ejs

app.set('views', path.join(__dirname, 'views'))// 设置存放模板文件的目录
app.set('view engine', 'ejs')// 设置模板引擎为 ejs

    通过 app.set 设置模板引擎为 ejs 和存放模板的目录。在 myblog 下新建 views 文件夹,在 views 下新建 users.ejs.

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
      body {padding: 50px;font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;}
    </style>
  </head>
  <body>
    <h1><%= name.toUpperCase() %></h1>
    <p>hello, <%= name %></p>
  </body>
</html>

ejs 常用标签:

  1. <% code %>:运行 JavaScript 代码,不输出
  2. <%= code %>:显示转义后的 HTML内容
  3. <%- code %>:显示原始 HTML 内容

routes/user.js

router.get('/:name', function (req, res) {
  res.render('users', {
    name: req.params.name
  })
})

        通过调用 res.render 函数渲染 ejs 模板,res.render 第一个参数是模板的名字,这里是 users 则会匹配 views/users.ejs,第二个参数是传给模板的数据,这里传入 name,则在 ejs 模板中可使用 name。

5. 中间件与next

     express 中的中间件(middleware)就是用来处理请求的,当一个中间件处理完,可以通过调用 next() 传递给下一个中间件,如果没有调用 next(),则请求不会往下传递

const express = require('express')
const app = express()

app.use(function (req, res, next) {
  console.log('1')
  next()
})

app.use(function (req, res, next) {
  console.log('2')
  res.status(200).end()
})

app.listen(3000)

// 输出  1 
//       2

6. node创建一个博客:包含登录、注册、发表文章等功能

目录结构:

  1. models: 存放操作数据库的文件
  2. public: 存放静态文件,如样式、图片等
  3. routes: 存放路由文件
  4. views: 存放模板文件
  5. index.js: 程序主文件
  6. package.json: 存储项目名、描述、作者、依赖等等信息

对应模块的作用:

  1. express: web 框架
  2. express-session: session 中间件
  3. connect-mongo: 将 session 存储于 mongodb,结合 express-session 使用
  4. connect-flash: 页面通知的中间件,基于 session 实现
  5. ejs: 模板
  6. express-formidable: 接收表单及文件上传的中间件
  7. config-lite: 读取配置文件
  8. marked: markdown 解析
  9. moment: 时间格式化
  10. mongolass: mongodb 驱动
  11. objectid-to-timestamp: 根据 ObjectId 生成时间戳
  12. sha1: sha1 加密,用于密码加密
  13. winston: 日志
  14. express-winston: express 的 winston 日志中间件

config-lite:   是一个轻量的读取配置文件的模块

config/default.js

module.exports = {
  port: 3000,
  session: {
    secret: 'myblog',
    key: 'myblog',
    maxAge: 2592000000
  },
  mongodb: 'mongodb://localhost:27017/myblog'
}

配置释义:

  1. port: 程序启动要监听的端口号
  2. session: express-session 的配置信息,后面介绍
  3. mongodb: mongodb 的地址,以 mongodb:// 协议开头,myblog 为 db 名

1. 会话

cookie 与 session 的区别

  1. cookie 存储在浏览器(有大小限制),session 存储在服务端(没有大小限制)
  2. 通常 session 的实现是基于 cookie 的,session id 存储于 cookie 中
  3. session 更安全,cookie 可以直接在浏览器查看甚至编辑

    通过引入 express-session 中间件实现对会话的支持:

const session = require('express-session')

app.use(session(options))

2. 页面通知

当我们操作成功时需要显示一个成功的通知,如登录成功跳转到主页时,需要显示一个 登陆成功的通知;当我们操作失败时需要显示一个失败的通知。

connect-flash 是基于 session 实现的,它的原理很简单:

req.session.flash={}    //设置初始值
req.flash(name, value)  //设置这个对象下的字段和值
req.flash(name) //获取这个对象下的值,同时删除这个字段,实现了只显示一次刷新后消失的功能。

3. 权限控制

我们可以把用户状态的检查封装成一个中间件,在每个需要权限控制的路由加载该中间件,即可实现页面的权限控制。

middlewares/check.js

module.exports = {
  checkLogin: function checkLogin (req, res, next) {
    if (!req.session.user) {
      req.flash('error', '未登录')
      return res.redirect('/signin')
    }
    next()
  },

  checkNotLogin: function checkNotLogin (req, res, next) {
    if (req.session.user) {
      req.flash('error', '已登录')
      return res.redirect('back')// 返回之前的页面
    }
    next()
  }
}

routes/signout.js

const checkLogin = require('../middlewares/check').checkLogin

// GET /signout 登出
router.get('/', checkLogin, function (req, res, next) {
  res.send('登出')
})

index.js

const path = require('path')
const express = require('express')
const session = require('express-session')
const MongoStore = require('connect-mongo')(session)
const flash = require('connect-flash')
const config = require('config-lite')(__dirname)
const routes = require('./routes')

const app = express()
// session 中间件
app.use(session({
  name: config.session.key, // 设置 cookie 中保存 session id 的字段名称
  secret: config.session.secret, // 通过设置 secret 来计算 hash 值并放在 cookie 中,使产生的 signedCookie 防篡改
  resave: true, // 强制更新 session
  saveUninitialized: false, // 设置为 false,强制创建一个 session,即使用户未登录
  cookie: {
    maxAge: config.session.maxAge// 过期时间,过期后 cookie 中的 session id 自动删除
  },
  store: new MongoStore({// 将 session 存储到 mongodb
    url: config.mongodb// mongodb 地址
  })
}))
// flash 中间件,用来显示通知
app.use(flash())

4.  变量:app.locals 和 res.locals

app.locals 上通常挂载常量信息(如博客名、描述、作者这种不会变的信息),res.locals 上通常挂载变量信息,即每次请求可能的值都不一样(如请求者信息,res.locals.user = req.session.user)。

index.js, 在 routes(app) 上一行添加如下代码:

// 设置模板全局常量
app.locals.blog = {
  title: pkg.name,
  description: pkg.description
}

// 添加模板必需的三个变量
app.use(function (req, res, next) {
  res.locals.user = req.session.user
  res.locals.success = req.flash('success').toString()
  res.locals.error = req.flash('error').toString()
  next()
})

这样在调用 res.render 的时候就不用传入这四个变量了,express 为我们自动 merge 并传入了模板,所以我们可以在模板中直接使用这四个变量。

5. mongolass

我们使用 Mongolass 这个模块操作 mongodb 进行增删改查。

lib/mongo.js:

const config = require('config-lite')(__dirname) //配置文件
const Mongolass = require('mongolass')
const mongolass = new Mongolass()
mongolass.connect(config.mongodb)

用户模型设计:

exports.User = mongolass.model('User', {
  name: { type: 'string', required: true },
  password: { type: 'string', required: true },
  avatar: { type: 'string', required: true },
  gender: { type: 'string', enum: ['m', 'f', 'x'], default: 'x' },
  bio: { type: 'string', required: true }
})
exports.User.index({ name: 1 }, { unique: true }).exec()// 根据用户名找到用户,用户名全局唯一

定义了用户表的 schema,生成并导出了 User 这个 model,同时设置了 name 的唯一索引,保证用户名是不重复的

6. 注册与文件上传

index.js

使用 express-formidable 处理 form 表单(包括文件上传):

// 处理表单及文件上传的中间件
app.use(require('express-formidable')({
  uploadDir: path.join(__dirname, 'public/img'), // 上传文件目录
  keepExtensions: true// 保留后缀
}))

models/users.js

const User = require('../lib/mongo').User

module.exports = {
  // 注册一个用户
  create: function create (user) {
    return User.create(user).exec()
  }
}

6. 404页面

router/index.js

// 404 page
app.use(function (req, res) {
  if (!res.headersSent) {
    res.status(404).render('404')
  }
})

views/404.ejs: 用了腾讯公益的 404 页面

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title><%= blog.title %></title>
    <script type="text/javascript" src="http://www.qq.com/404/search_children.js" charset="utf-8"></script>
  </head>
  <body></body>
</html>

7. 复用页面通知

将错误信息用页面通知展示的功能,刷新页面将会跳转到主页并显示『权限不足』的红色通知

index.js:

app.use(function(err,req,res,next) {
  console.error(err)
  req.flash('error', err.message)
  res.redirect('/posts')
})

8. 记录日志

我们使用 winston 和 express-winston 记录日志。([email protected]

winston 将正常请求的日志打印到终端并写入了 logs/success.log,将错误请求的日志打印到终端并写入了 logs/error.log

注意:记录正常请求日志的中间件要放到 routes(app) 之前,记录错误请求日志的中间件要放到 routes(app) 之后。

const winston = require('winston')
const expressWinston = require('express-winston')


// 正常请求的日志
app.use(expressWinston.logger({
  transports: [
    new (winston.transports.Console)({
      json: true,
      colorize: true
    }),
    new winston.transports.File({
      filename: 'logs/success.log'
    })
  ]
}))
// 路由
routes(app)
// 错误请求的日志
app.use(expressWinston.errorLogger({
  transports: [
    new winston.transports.Console({
      json: true,
      colorize: true
    }),
    new winston.transports.File({
      filename: 'logs/error.log'
    })
  ]
}))

9.   .gitignore 托管时忽略部分文件

线上配置、本地调试的 logs 以及 node_modules 添加到 git 的版本控制中,这个时候就需要 .gitignore 文件了

.gitignore

config/*
!config/default.*
npm-debug.log
node_modules
coverage

.pubilc/img/.gitignore

git 会忽略 public/img 目录下所有上传的头像,而不忽略 public/img 

# Ignore everything in this directory
*
# Except this file
!.gitignore

猜你喜欢

转载自blog.csdn.net/weixin_41892205/article/details/81330730