Node.js增删改查小demo

185 阅读3分钟

客户端(clien.js)

node clien.js --add --delete --modify --search
const http = require('http');
const URL = require('url').URL;
const command = process.argv
const host = 'http://localhost:3001/api/'
const operators = {
  ADD: 'add', // --add
  DEIELE: 'delete', // --delete
  MODIFY: 'modify', // --modify
  SEARCH: 'search' // --search
}
const baseConfig = {
  hostname: 'localhost',
  port: 3001
}

if(command.includes("--"+operators.ADD)) {
  // console.log()
  const req = http.request(
    {
      ...baseConfig,
      path: '/api/'+ operators.ADD,
      method: 'POST',
      query:''
    },
    res => {
      // res.setEncoding('utf8'); // 如果服务端没有设置Content-Type这里就需要设置utf8,进行解析
      let data = '';
      res.on('data',chunk=>{
        data+=chunk;
      })
      res.on('end',()=>{
        console.log('add:',data)
      })
    }
  )

 req.on('error',err=>{
   console.log('appear error in process of add:',err);
 })

 req.write(JSON.stringify({
   id: 100,
   name: 'test',
   age: 100
 }))
 // 可写流必须注意写入完成
 req.end()

}

if(command.includes('--'+operators.DEIELE)) {
  /**
   * 删除是一个修改数据库的操作,为了安全起见,就算只使用id我们也依旧使用post请求,保证我们不会误操作
   */
  const req = http.request(
    {
      ...baseConfig,
      path: '/api/'+ operators.DEIELE+'?id=666',
      method: 'POST',
      query: ''
    },
    res => {
      let data = '';
      res.on('data',chunk=> {
        data += chunk;
      })

      res.on('end',()=> {
        console.log('delete:',data)
      })
    }
  )

  req.on('error',err=>{
    console.log('appear error in process of delete data:',err)
  })

  req.write(JSON.stringify({}))

  req.end()
}

if(command.includes('--'+operators.MODIFY)) {
  const req = http.request(
    {
      ...baseConfig,
      path: '/api/'+ operators.MODIFY+'?id=6',
      method: 'POST',
      query: ''
    },
    res => {
      let data = '';
      res.on('data',chunk=>{
        data += chunk;
      })

      res.on('end',()=>{
        console.log('modify:',data)
      })
    }
  )

  req.on('error',err=>{
    console.log('appear error in process of modify:',err)
  })

  req.write(JSON.stringify({
    name: 'wj',
    age: 18
  }))

  req.end()
}

if(command.includes("--" + operators.SEARCH)) {
  const req = http.get(
    /** 使用new url.URL(path,host) 构造url对象 */
    new URL(operators.SEARCH,host).href,
    /** 
     * 响应(response)回调: response 是ReadableStream
     */
    res => {
      let data = ''
      res.on('data',chunk=>{
        data +=chunk;
      })
      res.on('end',()=>{
        console.log('http response by method called http.get():',data)
      })
    }
  )
  /**
   * http.get 返回一个可写流 request
   */
  req.on('error',err => {
    console.log('The error is catched in http.get():',err)
  })
}

服务端(server.js)

node server.js
/** 支持增删改查服务器 */
const http = require('http');
const url = require('url');
const path = require('path')

const operators = {
  ADD: 'add', // --add
  DEIELE: 'delete', // --delete
  MODIFY: 'modify', // --modify
  SEARCH: 'search' // --search
}

const operatorFns = {
  add(item) {
    console.log('添加中...',item)
    return {
      data: '添加成功!',
      errmsg: null,
      errcode: 0
    }
  },
  delete(id) {
    console.log('删除中...',id)
    return {
      data: "删除成功!",
      errmsg: null,
      errcode: 0
    }
  },
  modify(id,item) {
    console.log('更新中...',id,item)
    return {
      data: "更新成功!",
      errmsg: null,
      errcode: 0
    }
  },
  search() {
    return Array.from(
      {
        length: 10
      },
      (__, index) => ({
        id: index + 1,
        name: "小明" + index + 1,
        age: 18
      })
    )
  }
}

function createCheck(pathname,method) {
  return function(targetPath,targetMethod) {
    return pathname === '/api/'+ targetPath && method === targetMethod
  }
}

function runTaskInRoute(req,body) {
  const urlObj = url.parse(req.url,true);
  const check = createCheck(urlObj.pathname,req.method);
  if(check(operators.ADD,'POST')) {
    const result = operatorFns.add(body);
    return result;
  }

  if(check(operators.DEIELE,'POST')) {
    const result = operatorFns.delete(urlObj.query.id)
    return result;
  }

  if(check(operators.MODIFY,'POST')) {
    const result = operatorFns.modify(urlObj.query.id,body)
    return result;
  }

  if(check(operators.SEARCH,'GET')) {
    const result = operatorFns.search();
    return result;
  }
}

function getBodyAsync(req) {
  return new Promise((resolve,reject)=>{
    if(req.method !== "POST") {
      resolve({})
      return;
    }

    let body = '';
    req.on('data',(chunk)=>{
      body+=chunk;
    })

    req.on('end',()=>{
      resolve(JSON.parse(body))
    })
  })
}

const app = http.createServer((req,res)=>{
  getBodyAsync(req)
  .then(body=>{
    const result = runTaskInRoute(req,body);
    if(result) {
      res.writeHead(200,{
        'Conten-Type':'application/json;charset=UTF-8'
      })
      res.end(JSON.stringify(result))
    }else {
      res.writeHead(404,{
        'Content-Type':'text/html'
      })
      res.end('404 not found')
    }
  })
})


app.listen(3001,()=>{
  console.log('Port 3001 started successfully!')
})

常用模块

url

  • url.parse(urlString[,parseQueryString[,slashesDenoteHost]])
    • urlString:url字符串
    • parseQueryString: 是否解析query,将type=2形式解析成{type:2},默认不解析
    • slasheDenotoHost:
      • 默认为false,则//foo/bar形式字符串将被解析成{pathname:'//foo/bar'}.
      • 如果设置为true,则//foo/bar将被解析成{host:'foo',pathname:'/bar'}.
const url = require('url');
console.log(
  url.parse(
    'https://api.xdclass.net/pub/api/v1/web/product/find_list_by_type?type=2',
    // 解析query,默认不解析query
    true,
    // 将双斜杠后面的解析成host,默认双斜杠不解析为host
    true
  )
)
// Url {
//   protocol: 'https:',
//   slashes: true,
//   auth: null,
//   host: 'api.xdclass.net',
//   port: null,
//   hostname: 'api.xdclass.net',
//   hash: null,
//   search: '?type=2',
//   query: [Object: null prototype] { type: '2' },
//   pathname: '/pub/api/v1/web/product/find_list_by_type',
//   path: '/pub/api/v1/web/product/find_list_by_type?type=2',
//   href: 'https://api.xdclass.net/pub/api/v1/web/product/find_list_by_type?type=2'
// }

console.log(
  url.parse(
    'https://api.xdclass.net/pub/api/v1/web/product/find_list_by_type?type=2',
    // 解析query
    false,
    //  将双斜杠后面的解析成host
    true
  )
)

// Url {
//   protocol: 'https:',
//   slashes: true,
//   auth: null,
//   host: 'api.xdclass.net',    
//   port: null,
//   hostname: 'api.xdclass.net',
//   hash: null,
//   search: '?type=2',
//   query: 'type=2',   (第二个参数为false,所以不解析这里)
//   pathname: '/pub/api/v1/web/product/find_list_by_type',
//   path: '/pub/api/v1/web/product/find_list_by_type?type=2',
//   href: 'https://api.xdclass.net/pub/api/v1/web/product/find_list_by_type?type=2'
// }

nodemon(重启工具)

npm install -g nodemon
npm install -g cnpm --registry=https://registry.npm.taobao.org

常见问题

跨域

浏览器同源策略:协议+域名+端⼝三者相同就是同源。
http://www.baidu.com/a.js http://www.baidu.com/b.js
https://www.baidu.com/a.js http://www.baidu.com/a.js 协议不同
https://www.baidu.com:8080/a.js https://www.baidu.com/a.js 端⼝不同
https://www.baidu.com:8080/a.js https://www.a.com:8080/a.js 域名不同
跨域:协议、域名、端⼝三者任意⼀个不同就是跨域。
// 设置允许跨域的域名,*代表允许任意域名跨域
 res.setHeader("Access-Control-Allow-Origin","*");