Nodejs开发技巧

in STEEM CN/中文3 months ago

nodejs.jpg

下载与资源

Nodejs官网 |
文档 |
中文社区 |
webstorm |
代码规范 |
npm |
cnpm |
express |
HapiJS开发手册

Nodejs安装

//windows
直接下载安装

//ubuntu
利用nvm: https://github.com/nvm-sh/nvm
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

// 注意,运行代码之后需要重新打开终端。
// 重新打开终端并输入nvm,即可看到nvm已经可以使用了。
nvm ls-remote --lts  以列出所有的LTS版本node。
nvm install --lts  自动安装最新LTS版本的node(Latest LTS Version: 12.16.1 (includes npm 6.13.4))

node -v
//v12.16.1
npm -v
//6.13.4

npm

1、npm init -y           //初始化安装
2、npm install 包名 –-save  //下载并保存依赖项(package.json)
  npm i –S //简写
  npm update express //更新
3、npm uninstall 包名
4、npm help   npm init --help
5、npm config set registry https://registry.npm.taobao.org  //把淘宝镜像设成默认
  npm config list //查看配置信息
  (npm install –global cnpm /切换到淘宝镜像工具
  npm install 包名 --registry=https://registry.npm.taobao.org  //直接使用淘宝镜像源)
  registry = https://registry.npmjs.org/  //官方默认源
6、nodemon  //自动重启服务器
  npm install nodemon --global  
  node app.js  =>   nodemon app.js

Node.js的概念

  • JavaScript 运行时。既不是语言,也不是框架,它是一个平台。
  • Node.js 中的 JavaScript
    • 没有 BOM、DOM
    • 在 Node 中为 JavaScript 提供了一些服务器级别的 API
      • 文件操作的能力
      • http服务的能力
    • EcmaScript
      • 变量
      • 方法
      • 数据类型
      • 内置对象
      • Array
      • Object
      • Date
      • Math
    • 模块系统
      • 在 Node 中没有全局作用域的概念
      • 在 Node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件
      • require 加载只能是执行其中的代码,文件与文件之间由于是模块作用域,所以不会有污染的问题
        • 模块完全是封闭的
        • 外部无法访问内部
        • 内部也无法访问外部
      • 模块作用域固然带来了一些好处,可以加载执行多个文件,可以完全避免变量命名冲突污染的问题
      • 在每个模块中,都提供了一个对象:exports (modole.exports),该对象默认是一个空对象
      • 需要被外部访问使用的成员手动的挂载到 exports 接口对象中
    • 核心模块
      • 核心模块是由 Node 提供的一个个的具名的模块,它们都有自己特殊的名称标识,例如
        • fs 文件操作模块
        • http 网络服务构建模块
        • os 操作系统信息模块
        • path 路径处理模块
      • 所有核心模块在使用的时候都必须手动的先使用 require 方法来加载,然后才可以使用,例如:var fs = require('fs')
    • http
      • require
      • 端口号
        • ip 地址定位计算机
        • 端口号定位具体的应用程序
      • Content-Type
        • 服务器最好把每次响应的数据是什么内容类型都告诉客户端,而且要正确的告诉
        • 不同的资源对应的 Content-Type 是不一样,具体参照:http://tool.oschina.net/commons
        • 对于文本类型的数据,最好都加上编码,目的是为了防止中文解析乱码问题
          // 在 http 协议中,Content-Type 就是用来告知对方我给你发送的数据内容是什么类型
          // res.setHeader('Content-Type', 'text/plain; charset=utf-8')
      • 通过网络发送文件
        • 发送的并不是文件,本质上来讲发送是文件的内容
        • 当浏览器收到服务器响应内容之后,就会根据你的 Content-Type 进行对应的解析处理

fs模块

浏览器中的 JavaScript 是没有文件操作的能力的,但是 Node 中的 JavaScript 具有文件操作的能力。

fs 是 file-system 的简写,就是文件系统的意思。在 Node 中如果想要进行文件操作,就必须引入 fs 这个核心模块。

//使用 require 方法加载 fs 核心模块
var fs = require('fs')

//读取文件
  第一个参数就是要读取的文件路径
  第二个参数是一个回调函数
    成功
      data 数据
      error null
    失败
      data undefined没有数据
      error 错误对象

fs.readFile('./data/a.txt', function (error, data) {
  //  <Buffer 68 65 6c 6c 6f 20 6e 6f 64 65 6a 73 0d 0a>
  //  文件中存储的其实都是二进制数据 0 1,这里是16进制
  //  所以我们可以通过 toString 方法把其转为我们能认识的字符
   console.log(data.toString())
})

写文件

var fs = require('fs')
// 第一个参数:文件路径
// 第二个参数:文件内容
// 第三个参数:回调函数
//    成功:
//      文件写入成功
//      error 是 null
//    失败:
//      文件写入失败
//      error 就是错误对象
fs.writeFile('./data/你好.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
  // console.log('文件写入成功')
  // console.log(error)
  if (error) {
    console.log('写入失败')
  } else {
    console.log('写入成功了')
  }
})

核心模块os和path

// 用来获取机器信息的
var os = require('os')

// 用来操作路径的
var path = require('path')

// 获取当前机器的 CPU 信息
console.log(os.cpus())

// memory 内存
console.log(os.totalmem())

// 获取一个路径中的扩展名部分
// extname extension name
console.log(path.extname('c:/a/b/c/d/hello.txt'))

http模块

// ip 地址用来定位计算机
// 端口号用来定位具体的应用程序
// 所有需要联网通信的应用程序都会占用一个端口号
var http = require('http') 
var server = http.createServer()

// 2. 监听 request 请求事件,设置请求处理函数
server.on('request', function (req, res) {
  console.log('收到请求了,请求路径是:' + req.url)
  console.log('请求我的客户端的地址是:', req.socket.remoteAddress, req.socket.remotePort)
  res.end('hello nodejs')
})

server.listen(3000, function () {
  console.log("服务器启动成功,端口号3000, http://127.0.0.1:3000")
})

模块的导出与导入

//导出的变量和函数,都在exports对象中
//可以默认为每个模块中都有一个modole对象,
//modole.exports = exports
var foo = 'bbb'
exports.foo = 'hello'
exports.add = function (x, y) {
  return x + y
}

//导出一个默认的变量或方法
modole.exports = "hello"

//导入 
// require 方法有两个作用:
//  1. 加载文件模块并执行里面的代码
//  2. 拿到被加载文件模块导出的接口对象, exports 
var bExports = require('./b')
console.log(bExports.foo)
console.log(bExports.add(10, 30))

第三方模块导入规则

  • 凡是第三方模块都必须通过 npm 来下载

  • 使用的时候就可以通过 require('包名') 的方式来进行加载才可以使用

  • 不可能有任何一个第三方包和核心模块的名字是一样的

  • 先找到当前文件所处目录中的 node_modules 目录

    node_modules/art-template
    node_modules/art-template/package.json 文件
    node_modules/art-template/package.json 文件中的 main 属性
      main 属性中就记录了 art-template 的入口模块

      如果 package.json 文件不存在或者 main 指定的入口模块是也没有
      则 node 会自动找该目录下的 index.js,也就是说 index.js 会作为一个默认备选项
   
      如果以上所有任何一个条件都不成立,则会进入上一级目录中的 node_modules 目录查找。如果上一级还没有,则继续往上上一级查找。如果直到当前磁盘根目录还找不到,最后报错:can not find module xxx

nodemon自动重启

npm install nodemon --global
nodemon --version
nodemon app.js  

Express

文档

cnpm install express -–save
//app.js
var express = require('express')
var app = express()
app.get('/', function (req, res) {
    res.send('hello world')
})
app.listen(3000, function () {
    console.log('express running http://127.0.0.1:3000')
})


// 基本路由
请求方法,请求路径,请求处理函数
app.get('/', function(req, res){
  res.send('hello world!')
})

app.post('/', function(req, res){
  res.send('get a post')
})

// 请求静态资源
app.use('/public/', express.static('./public/'))
  也可以省略前面的参数(路径不用写public):
  app.use(express.static('./public/'))

//get获取参数
app.get('/post', function(req, res){
  console.log(req.query)
}) 

//跳转
res.redirect('/')

express-generator

cnpm install express-generator -g
express book_service
cd book_service
cnpm install
SET DEBUG=book-service:* & npm start
// node bin/www

art-template模板

cnpm install --save art-template
cnpm install --save express-art-template
//app.js
var express = require('express')
var app = express()
app.engine('html', require('express-art-template'))  //配置模板引擎
app.get('/', function (req, res) {
    res.render('index.html', {})  
    //默认渲染 views中的文件
    //req.query 得到get的请求体
})
app.listen(3000, function () {
    console.log('aoo running http://127.0.0.1:3000')
})

body-parser

在Express中获取POST请求, 请求参数在req.body

cnpm install --save body-parser

//app.js
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false}))
app.use(bodyParser.json())

app.post('/register', async function(req, res){
    console.log('register123', req.body)

    let result = await create_account(req.body.username, req.body.password)
    if(result === "ok"){
      //创建成功
      res.send('ok')
    }else{
      res.send(result)
    }
})

express-router

//app.js
var router = require('./router')
// 把路由容器挂载到 app 服务中
app.use(router)

//router.js
// 专门用来包装路由的
var express = require('express')
// 1. 创建一个路由容器
var router = express.Router()
router.get('/students/new', function (req, res) {
  res.render('new.html')
})

forever守护进程

$ sudo npm install forever -g   //安装
$ forever start app.js          //启动
$ forever stop app.js           //关闭
$ forever start -l forever.log -o out.log -e err.log app.js   //输出日志和错误

// 1. 简单的启动
//日志默认它会放到~/.forever/5er-.log
forever start app.js

forever list  //查看列表
ps -aux | grep forever

// 2. 指定forever信息输出文件,当然,默认它会放到~/.forever/app.log
forever start -l app.log app.js

// 3. 指定app.js中的日志信息和错误日志输出文件,
//  -o 就是console.log输出的信息,-e 就是console.error输出的信息
forever start -o out.log -e err.log app.js

// 4. 追加日志,forever默认是不能覆盖上次的启动日志,
//  所以如果第二次启动不加-a,则会不让运行
forever start -l forever.log -a app.js

// 5. 监听当前文件夹下的所有文件改动
forever start -w app.js

回调函数callback

  • 一种数据类型
  • 参数
  • 返回值
  • 一般情况下,把函数作为参数的目的就是为了获取函数内部的异步操作结果
  • JavaScript 单线程、事件循环
//用回调函数获取异步的结果
function add(x, y, callback) {
  console.log(1)
  setTimeout(function () {
    var ret = x + y
    callback(ret)
  }, 1000)
}

add(10, 20, function (ret) {
  console.log(ret)
})

//eg:
fs.readFile('./data/tt.txt', function (error, data) {
    console.log(data.toString())
 })

// 注意:凡是需要得到一个函数内部异步操作的结果必须通过回调函数
// 例如: setTimeout,readFile,writeFile

操作MongoDB

操作MongoDB

跨域

文档

app.all("*",function(req,res,next){
    //设置允许跨域的域名,*代表允许任意域名跨域
    res.header("Access-Control-Allow-Origin","*");
    //允许的header类型
    res.header("Access-Control-Allow-Headers","content-type");
    //跨域允许的请求方式 
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options')
        res.send(200);  //让options尝试请求快速结束
    else
        next();
})