create account

Nodejs开发技巧 by lemooljiang

View this thread on: hive.blogpeakd.comecency.com
· @lemooljiang ·
$9.16
Nodejs开发技巧
![nodejs.jpg](https://steemjiang.com:8081/ipfs/QmeGyGfDvAkfqE4njraJGgDoQB7a7oZUK8NSKPS9i3JbWr)

- [下载与资源](#下载与资源)
- [Nodejs安装](#nodejs安装)
- [npm](#npm)
- [Node.js的概念](#nodejs的概念)
- [fs模块](#fs模块)
- [写文件](#写文件)
- [核心模块os和path](#核心模块os和path)
- [http模块](#http模块)
- [模块的导出与导入](#模块的导出与导入)
- [第三方模块导入规则](#第三方模块导入规则)
- [nodemon自动重启](#nodemon自动重启)
- [Express](#express)
- [express-generator](#express-generator)
- [art-template模板](#art-template模板)
- [body-parser](#body-parser)
- [express-router](#express-router)
- [forever守护进程](#forever守护进程)
- [回调函数callback](#回调函数callback)
- [操作MongoDB](#操作mongodb)
- [跨域](#跨域)   

## 下载与资源 
[Nodejs官网 |](https://nodejs.org)
[文档 |](https://nodejs.org/dist/latest-v14.x/docs/api/)
[中文社区 |](https://cnodejs.org)
[webstorm |](http://www.jetbrains.com/webstorm)
[代码规范 |](https://standardjs.com/rules.html)
[npm |](https://www.npmjs.com)
[cnpm |](http://npm.taobao.org)
[express |](http://expressjs.com/)
[HapiJS开发手册](https://blog.csdn.net/hffyyg/article/details/86616555)

## Nodejs安装
```js
//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
```js
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 这个核心模块。
```js
//使用 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())
})
```

## 写文件 
```js
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
```js
// 用来获取机器信息的
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模块
```js
// 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")
})
```

## 模块的导出与导入
```js
//导出的变量和函数,都在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
[文档](https://www.runoob.com/nodejs/nodejs-express-framework.html)

```js
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
```js
cnpm install express-generator -g
express book_service
cd book_service
cnpm install
SET DEBUG=book-service:* & npm start
// node bin/www
```

## art-template模板
```js
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`中
```js
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
```js
//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守护进程
```js
$ 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 单线程、事件循环
```js
//用回调函数获取异步的结果
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](https://www.runoob.com/nodejs/nodejs-mongodb.html)

## 跨域
[文档](https://blog.csdn.net/u012149969/article/details/81145144)
```js
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();
})
```
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
properties (23)
authorlemooljiang
permlinknodejs
categoryhive-105017
json_metadata{"tags":["cn","nodejs","javascript","npm","server"],"image":["https://steemjiang.com:8081/ipfs/QmeGyGfDvAkfqE4njraJGgDoQB7a7oZUK8NSKPS9i3JbWr"],"links":["#下载与资源"],"app":"hiveblog/0.1","format":"markdown","description":"Nodejs的一些开发心得,笔记","author":"lemooljiang"}
created2021-06-19 09:56:57
last_update2021-06-19 09:56:57
depth0
children0
last_payout2021-06-26 09:56:57
cashout_time1969-12-31 23:59:59
total_payout_value4.664 HBD
curator_payout_value4.493 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length9,726
author_reputation438,608,506,193,732
root_titleNodejs开发技巧
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id104,425,470
net_rshares22,718,422,964,869
author_curate_reward""
vote details (49)