Front-end advanced full-stack entry-level tutorial nodeJs blog development (1) build environment and routing

When reading this article, you need to have a certain foundation in the front-end, and you want to advance to the full stack, or understand the working method of the back-end. Reading, can better improve the understanding of the separation and docking before and after, this article will only guide the operation of the overview , Back-end development. easy to understand.

Article Directory

1. Build a development environment

tipsThe following comments // are omitted. . . . The unmodified parts are omitted

We first create the folder nativBlog

Then use npm init -y to initialize a project

Insert picture description here

Install nodemon to restart node automatically

npm i nodemon -D

Install cross-env to control the development environment

npm i cross-env -D

Follow the steps below to create and modify files, build a basic nodeSever, and return certain data

File structure

├─app.js
├─package.json
├─src
├─bin
|  └www.js

www.js

const http = require('http')

const PORT = 8000
const serverHandle = require('../app')

const server = http.createServer(serverHandle)
server.listen(PORT)
console.log('已开启 8000端口');

app.js

const serverHandle = (req,res)=>{
  // 设置返回格式 JSON
  res.setHeader('Content-type','application/json')
   //模拟一下假数据 
  const resData = {
    name:'admin',
    env:process.env.NODE_ENV
  }

  res.end(
    JSON.stringify(resData)
  )
}

module.exports = serverHandle

Add start command

package.json

{
  "name": "native-blog",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "cross-env NODE_ENV=dev nodemon ./bin/www.js",
    "prd": "cross-env NODE_ENV=production nodemon ./bin/www.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {},
  "devDependencies": {
    "cross-env": "^7.0.3",
    "nodemon": "^2.0.7"
  }
}

Run it

Then open the browser or postman to test

npm run dev
Insert picture description here

Second, build routing

The concept of routing and API

API:

A term for the connection between front-end and back-end, and different ends (subsystems)

The front-end only needs to know what the url (route) is, the delivery method and the parameters, and does not need to know how to implement it

routing:

Part of the API,

A definition inside the back-end system,

For example, to implement an api, you need to define a router, controller db model, etc.

(1) Build basic routing

The following is the interface we need to establish

Insert picture description here

We distinguish between blog and user 2 parts to create files

├─src
|  ├─router //处理路由
|  |   ├─blog.js
|  |   └user.js

blog.js

const  handleBlogRouter = (req,res) =>{
console.log('method:',req.method);
console.log(' req.path:', req.path);

  // 获取博客列表
  if(req.method ==='GET'&&  req.path ==='/api/blog/list') {
    console.log('进入2');
    
    return {
      msg:'这是获取博客列表的接口'
    }
  }
  // 获取博客详情
  if(req.method === 'GET'&&  req.path ==='/api/blog/detail') {
    return {
      msg:'这是获取博客详情的接口'
    }
  }
  // 新建一篇博客
  if(req.method === 'POST'&&  req.path ==='/api/blog/new') {
    return {
      msg:'这是新建博客列表的接口'
    }
  }
  // 更新博客列表
  if(req.method === 'POST'&&  req.path ==='/api/blog/update') {
    return {
      msg:'这是更新博客列表的接口'
    }
  }
  // 删除博客列表
  if(req.method === 'GET'&&  req.path ==='/api/blog/del') {
    return {
      msg:'这是删除博客列表的接口'
    }
  }
}
module.exports = handleBlogRouter

user.js

const handleUserRouter = (req,res)=>{
 
  // 登录
  if(req.method === 'POST' &&  req.path === '/api/user/login'){
    return {
      msg:'这是登录的接口'
    }
  }
}
module.exports = handleUserRouter

Modify the original app.jsto handle the request

const querystring = require('querystring') //引入原生模块解析get参数
const handleBlogRouter = require('./src/router/blog')
const handleUserRouter = require('./src/router/user')
const serverHandle = (req,res)=>{

    // 设置返回格式 JSON
    res.setHeader('Content-type','application/json')
  // 获取路径
    const url = req.url
    req.path = url.split('?')[0]
  // 解析query
    req.query = querystring.parse(url.split('?')[0])
    // 处理blog路由
    const blogData= handleBlogRouter(req,res)

    if(blogData){
      res.end(
        JSON.stringify(blogData)
      )
      return
    }

    // 处理user路由
    const userData= handleUserRouter(req,res)

    if(userData){
      res.end( 
        JSON.stringify(userData)
      )
      return
}
// 未命中路由返回404
res.writeHead(404,{"COntent-type":"text/plian"})
res.write("404 Not Found\n")
res.end()
}

module.exports = serverHandle

Through the previous step, we simply built a set of routing, and then used psotman to test it

Insert picture description here

OK, no problem, of course you need to try every interface

(2) Create the controller and model layers

File structure

├─src
|  ├─router //处理路由
|  |   ├─blog.js
|  |   └user.js
|  ├─model //建立数据模型
|  |   └resModel.js
|  ├─controller //处理业务逻辑
|  |     ├─blog.js
|  |     └user.js


To distinguish a fact, it is necessary to distinguish the hierarchy. The router only handles routing, www.js only creates sever, and controller only handles business logic.

model handles the returned data structure

At this point, the database has not been connected yet, but we have to pretend to simulate the real data return

First build the model

resModel.js

class BaseModel {
  constructor(data, message) {
      // 兼容判断是否传人2个参数
      if (typeof data === 'string') {
          this.message = data
          data = null
          message = null
      }
      if (data) {
          this.data = data
      }
      if (message) {
          this.message = message
      }
  }
}
 //成功的数据模型
class SuccessModel extends BaseModel {
  constructor(data, message) {
      super(data, message)
      this.errno = 0
  }
}

// 失败的数据模型
class ErrorModel extends BaseModel {
  constructor(data, message) {
      super(data, message)
      this.errno = -1
  }
}

module.exports = {
  SuccessModel,
  ErrorModel
}

Secondly, establish the controller layer

First do a simple fake data simulation,

blog.js

const getList = (author,keyword) =>{
	//模拟返回的数据,用promise模拟异步数据库操作
  const promise = new Promise((resolve,reject)=>{
    const data = [
      {
        id:1,
        title:"标题A",
        content:"内容A",
        createTime:1600410168761,
        author:"张三"
      },
      {
        id:2,
        title:"标题B",
        content:"内容B",
        createTime:1600410221493,
        author:"李四"
      }
    ]
    resolve(data)
  })
  return promise
}
module.exports = {
  getList
}

Then modify the processing of bolg.js under router, modify an interface to experience

blog.js

//导入controller
const {getList} = require('../controller/blog')
//导入model
const {SuccessModel,ErrorModel} = require('../model/resModel')
......省略未修改部分

// 获取博客列表
  if(req.method ==='GET'&&  req.path ==='/api/blog/list') {
    const author = "张三"
    const keyword = "标题A"
    
      const result = getList(author,keyword)
    return result.then(data =>{
        return new SuccessModel(data,'请求成功')
    })
  }
......省略未修改部分

app.js

...省略未修改部分

const serverHandle = (req,res)=>{
...省略未修改部分
            // 处理blog路由
        const blogResult= handleBlogRouter(req,res)
        if(blogResult){
          blogResult.then(blogData =>{
            if(blogData){
              res.end(
                JSON.stringify(blogData)
              )
            }
          })
          return
        }
        // // 处理user路由
        const userResult= handleUserRouter(req,res)
        if(userResult){
          userResult.then(userData=>{
            if(userData){
              res.end(
                JSON.stringify(userData)
              )
              return
            }
          })
        }
...省略未修改部分
}
module.exports = serverHandle

Use postman to test after modification

Insert picture description here

The test is successful, which means that our module planning is no problem

(3) Processing post request

We used get before. We haven't done any processing for post. Post is an asynchronous operation, so we need to use promise to deal with it.

Encapsulate the following method to process post

// 处理post请求
const getPostData = (req) => {
  const promise = new Promise((resolve, reject) => {
    // 不是post,get请求
      if (req.method !== 'POST') {
          resolve({})
          return
      }
      // post请求处理, 如果返回的格式不是json 返回一个空
      if (req.headers['content-type'] !== 'application/json') {
          resolve({})
          return
      }
      let postData = ''
      //   post数据其实是数据流,所以我们需要监听拼接数据
      req.on('data', chunk => {
          postData += chunk.toString()
      })
      req.on('end', () => {
        // 没有数据返回一个空
          if (!postData) {
              resolve({})
              return
          }
          resolve(
              JSON.parse(postData)
          )
      })
  })
  return promise
}

Then the app.jscomplete code is as follows, before processing the routing, first process the post request through the encapsulation method

const querystring = require('querystring')
const handleBlogRouter = require('./src/router/blog')
const handleUserRouter = require('./src/router/user')

// 处理post请求
const getPostData = (req) => {
  const promise = new Promise((resolve, reject) => {
    // 不是post,get请求
      if (req.method !== 'POST') {
          resolve({})
          return
      }
      // post请求处理, 如果返回的格式不是json 返回一个空
      if (req.headers['content-type'] !== 'application/json') {
          resolve({})
          return
      }
      let postData = ''
      req.on('data', chunk => {
          postData += chunk.toString()
      })
      req.on('end', () => {
        // 没有数据返回一个空
          if (!postData) {
              resolve({})
              return
          }
          resolve(
              JSON.parse(postData)
          )
      })
  })
  return promise
}

const serverHandle = (req,res)=>{

    // 设置返回格式 JSON
    res.setHeader('Content-type','application/json')
  // 获取路径
    const url = req.url
    req.path = url.split('?')[0]
    // 解析query
    req.query = querystring.parse(url.split('?')[1])
    // 处理post请求
    getPostData(req).then(postData=>{
          req.body = postData
            // 处理blog路由
        const blogResult= handleBlogRouter(req,res)
        if(blogResult){
          blogResult.then(blogData =>{
            if(blogData){
              res.end(
                JSON.stringify(blogData)
              )
            }
          })
          return
        }

        // // 处理user路由
        const userResult= handleUserRouter(req,res)
        if(userResult){
          userResult.then(userData=>{
            if(userData){
              res.end(
                JSON.stringify(userData)
              )
            }
          })
              return
        }
    
    // 未命中路由返回404
    res.writeHead(404,{"COntent-type":"text/plian"})
    res.write("404 Not Found\n")
    res.end()
  })

   
}

module.exports = serverHandle

Then modify a post interface to test it

controller

blog.js

...省略
const newBlog = (blogData = {}) =>{
  // blogData 包含 title content
  // 添加成功返回添加id,
    //模拟处理完成后返回数据
  const promise = new Promise((resolve,reject)=>{
    const data = {
      id:3
    }
    resolve(data)
  })
  return promise
}
module.exports = {
    ...省略
  newBlog
}

router

blog.js

const {
  ...省略
  newBlog} = require('../controller/blog')
 ...省略

  // 新建一篇博客
  if(req.method === 'POST'&&  req.path ==='/api/blog/new') {
          const result = newBlog(req.body)
      return result.then(data =>{
        return new SuccessModel(data,'添加成功')
    })
  }
 ...省略

Test it with postman,

Insert picture description here
Next, complete and simulate all the data

controller

blog.js

const getList = (author,keyword) =>{
  const promise = new Promise((resolve,reject)=>{
    const data = [
      {
        id:1,
        title:"标题A",
        content:"内容A",
        createTime:1600410168761,
        author:"张三"
      },
      {
        id:2,
        title:"标题B",
        content:"内容B",
        createTime:1600410221493,
        author:"李四"
      }
    ]
    resolve(data)
  })
  return promise
}
const getDetail = (id) =>{
  const promise = new Promise((resolve,reject)=>{
    const data = [
      {
        id:2,
        title:"标题B",
        content:"内容B",
        createTime:1600410221493,
        author:"李四"
      }
    ]
    resolve(data)
  })
  return promise
}
const newBlog = (blogData = {}) =>{
  // blogData 包含 title content
  // 添加成功返回添加id,
  const promise = new Promise((resolve,reject)=>{
    const data = {
      id:3
    }
    resolve(data)
  })
  return promise

}

const updateBlog = (id,blogData = {}) =>{
 // id 就是要更新博客的 id
    // blogData 是一个博客对象,包含 title content 属性
    const promise = new Promise((resolve,reject)=>{
     
      resolve(true)
    })
    return promise
}
const delBlog = (id,author) =>{
  // id 删除博客的id
  const promise = new Promise((resolve,reject)=>{
     
    resolve(true)
  })
  return promise
}

module.exports = {
  getList,
  getDetail,
  updateBlog,
  newBlog,
  delBlog
}

user.js

const login = (username, password) =>{
   const promise = new Promise((resolve,reject)=>{
     
    resolve(false)
  })
  return promise
 }

 module.exports = {
   login
 }

router

blog.js

const {
  getList,
  getDetail,
  updateBlog,
  newBlog,
  delBlog} = require('../controller/blog')
const {SuccessModel,ErrorModel} = require('../model/resModel')
const  handleBlogRouter = (req,res) =>{
  const method = req.method
  const id = req.query.id


console.log('method:',req.method);
console.log(' req.path:', req.path);

  // 获取博客列表
  if(method ==='GET'&&  req.path ==='/api/blog/list') {
    const author = req.query.author
    const keyword =req.query.keyword
    
    const result = getList(author,keyword)
    return result.then(data =>{
        return new SuccessModel(data,'请求成功')
    })
  }
  // 获取博客详情
  if(method === 'GET'&&  req.path ==='/api/blog/detail') {
    const result = getDetail(id)
    return result.then(data =>{
      return new SuccessModel(data,'请求成功')
  })
}
  // 新建一篇博客
  if(method === 'POST'&&  req.path ==='/api/blog/new') {
      const result = newBlog(req.body)
      return result.then(data =>{
        return new SuccessModel(data,'添加成功')
    })
   
  }
  // 更新博客列表
  if(method === 'POST'&&  req.path ==='/api/blog/update') {

    const result = updateBlog(id,req.body)
      
    return result.then(data =>{
      if(data){
        return new SuccessModel('修改成功')
      } else {
        return new ErrorModel('修改失败')
      }
     
  })
    
  }
  // 删除博客列表
  if(method === 'GET'&&  req.path ==='/api/blog/del') {
    const author = req.query.author
    const result = delBlog(id,author)
    return result.then(data =>{
      if(data){
        return new SuccessModel('删除成功')
      } else {
        return new ErrorModel('删除失败')
      }
     
  })
  }
}
module.exports = handleBlogRouter

user.js


const {login} = require('../controller/user')
const {SuccessModel,ErrorModel} = require('../model/resModel')


const handleUserRouter = (req,res)=>{
 
  // 登录
  if(req.method === 'POST' &&  req.path === '/api/user/login'){
 const {userName,passWord} = req.body
    const result = login(userName,passWord)
    return result.then(data =>{
      if(data){
        return new SuccessModel('登陆成功')
      } else {
        return new ErrorModel('登陆失败')
      }
  })
  }
}
module.exports = handleUserRouter