A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

我不是奶毛

初级黑马

  • 黑马币:

  • 帖子:

  • 精华:

© 我不是奶毛 初级黑马   /  2018-11-15 12:25  /  2465 人查看  /  1 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文


# nodejs

## nodejs是什么

- 是运行在服务器上的JavaScript
- 是一个javascript运行时环境,不是语言 不是框架 是一个环境 一个平台



##nodejs的特性

* 单线程
* 非阻塞IO
* 基于事件模型
* 服务端的javascript



## nodejs中的javascript

###ECMAScript

+ 也就是js的基本语法 node中同样适用
+ `没有bom 和 dom 的api`

###模块系统

+ 一些特性 :

* 在 Node 中没有全局作用域的概念

* 在 Node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件

* require 加载只能是执行其中的代码,文件与文件之间由于是模块作用域,所以不会有污染的问题

    - 模块完全是封闭的
    - 外部无法访问内部
    - 内部也无法访问外部

    - 模块作用域固然带来了一些好处,可以加载执行多个文件,可以完全避免变量命名冲突污染的问题

* 但是某些情况下,模块与模块是需要进行通信的
* 在每个模块中,都提供了一个对象:`exports`
* 该对象默认是一个空对象
* 你要做的就是把需要被外部访问使用的成员手动的挂载到 `exports` 接口对象中
* 然后谁来 `require` 这个模块,谁就可以得到模块内部的 `exports` 接口对象

    ####核心模块

    * 定义
        * 核心模块是由 Node 提供的一个个的具名的模块,它们都有自己特殊的名称标识,例如
          - fs 文件操作模块
          * http 网络服务构建模块
          * os 操作系统信息模块
          * path 路径处理模块
          * 。。。。
    * 所有核心模块在使用的时候都必须手动的先使用 `require` 方法来加载,然后才可以使用,例如:

      - `var fs = require('fs')`



## 系统核心模块

### http模块(http)(用于搭建服务器)

> 引入 模块 `var http = require('http')`

#### 搭建服务器

**注意 :一次响应对应一次请求**

```javascript

//引入http模块
var http = require('http')

//创建server服务
var server = http.createServer()

//监听请求
server.on('request',function (req,res) {
    console.log(req.url)
    //设置响应头中的contenttype为 utf-8 防止乱码
    res.setHeader('Content-Type', 'text/plain; charset=utf-8')
    //设置响应体 并 结束本次响应
    res.end('天干物燥 小心火烛')

})

//开启服务
server.listen('3000',function () {
    console.log('服务已经启动了~');
})
```

- 创建服务器 回调函数中的 req res 的 一些属性和方法

  *  属性: req.url  拿到的是请求的路径

  *  方法: res.setHeader('Content-Type', 'text/plain; charset=utf-8')

     设置响应头中的contenttype为 utf-8 防止乱码

  *  方法: res.write()  可以用来给客户端发送响应数据

  *  方法: res.end()

    不传参 :告诉客户端,我的话说完了,你可以呈递给用户了  

    传参('字符串') : 会将响应结束 并把字符串响应给客户端

  *  属性: req.socket.remoteAddress  用于获取请求的 客户端IP地址

  *  属性: req.socket.remotePort 用于获取请求的 客户端端口号

  *  属性: res.statuscode 设置状态码  301 表示永久重定向 302 表示临时重定向

     * 通常和res.setHeader('Location','/') 搭配使用 用于重定向 页面

### 文件系统模块(fs)

> ​        想用着个模块这得 先引入这个 模块 `var fs = require('fs')`

#### 一些文件操作相关api

- 读文件 操作 `fs.readFile()`

   ``` javascript
   fs.readFile('文件名',function(err,data){
       //如果出错 直接return 响应体信息
       //res 是创建服务器时的 响应体参数
       if (err) return res.end('出错啦!!!')
       res.end(data)
   })


   //这个方法可以传入第二个参数 是可选的 传了 就表示 返回的结果是utf-8 的字符
   fs.readFile('文件名','utf8',function(err,data){
       //如果出错 直接return 响应体信息
       //res 是创建服务器时的 响应体参数
       if (err) return res.end('出错啦!!!')
       res.end(data)
   })

   ```

- 写文件操作 `fs.writeFile`()

   ```javascript
   fs.writeFile('./data/你好.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
     // console.log('文件写入成功')
     // console.log(error)
     if (error) {
       console.log('写入失败')
     } else {
       console.log('写入成功了')
     }
   })
   ```

- 读取文件目录 `fs.readdir()`

   ```javascript

   fs.readdir('E:/wsTest', function (err, files) {
     if (err) {
       return console.log('目录不存在')
     }
     console.log(files)
      //这个返回的files 是一个数组
     //  [ '.idea', '.vscode', '24', 'node_modules', 'package-lock.json' ]
   })

   ```


### URL模块(url)

> 引入模块  一般用于解析 `var url = require('url')`

   #### api       

- url.parse('www.baidu.com?name=xxx&pwd=xxx',true) 返回一个 url对象
  + 如果有传第二个参数 true 那么其中的query 为装成对象        不传则是 name=xxx&pwd=xxx

   ```javascript
   Url {
     protocol: null,
     slashes: null,
     auth: null,
     host: null,
     port: null,
     hostname: null,
     hash: null,
     search: '?name=xxx&pwd=xxx',
     query: { name: 'xxx', pwd: 'xxx' },
     pathname: 'www.baidu.com',
     path: 'www.baidu.com?name=xxx&pwd=xxx',
     href: 'www.baidu.com?name=xxx&pwd=xxx'
   }

   ```



## npm

新版本node.js安装的时候会自动安上npm

- 是什么 ? `NodeJs中的包管理工具  ` [ `是一个网站`](https://www.baidu.com/link?url=m ... e5a000000065ba69444) 是一个命令行工具

- 可以用来干什么?  用来管理nodejs的包 下载安装第三方模块 也可以直接上传模块至网站

  ---


#### 怎么用? 一些npm 常用命令

  + npm init 在当前目录生成package.json文件  

      + npm init -y 可以跳过向导 直接在当前目录生成package.json文件

  + npm install 讲当前目录的package.json文件中的 依赖项全部下载安装

  + npm install 包名 下载这个包

      + npm install 包名 --save  下载这个包 并 在package.json中 添加信息至 依赖项中(dependencies )
      + npm install 包名@版本号 下载这个包的这个版本

  + npm  uninstall 包名  移除这个包

      + npm uninstall 包名 --save 移除这个包 并在package.json中的依赖也移除

+ npm help 查看使用帮助

+ npm 命令(install) --help 查看此命令的帮助 忘记简写可以这么用

+ npm -i npm -g 可以升级npm

  **所有install 可以简写成 i 所有 uninstall可以简写成 un -**

  **--save  -S  -- global -g**

  ---


#### npm被墙问题

- 因为npm服务器架设在国外 所以访问速度慢 怎么解决?
- 国内淘宝开发团队 搞了一个npm的镜像 cnpm
  - 在npm中 输入命令 安装cnpm `npm install cnpm -g` -g代表全局安装
  - 然后使用的时候 就得用 cnpm去下载安装第三方包(模块)
  - 不想安装cnpm怎么办? 改变npm的 资源库指向淘宝的镜像资源库(每10分钟同步一次) (个人理解)
    - 写进配置文件中 `npm config set registry htts://registry.npm.taobao.org`
    - 配置完之后 可以输入命令 `npm config  list `查看一下是否配置成功



## 第三方模块

**任何第三方模块都需要先用 npm 下载安装后 才能引入**

### art-template(art-template)

> 同样的 引入第三方模块也是先加载这个模块  `var template = require('art-template')`

---

#### 在nodejs中使用art-template  和 相关api

```javascript
//准备好 模板文件  tpl.html
fs.readFile('./tpl.html', function (err, data) {
  if (err) {
    return console.log('读取文件失败了')
  }
  // 默认读取到的 data 是二进制数据
  // 而模板引擎的 render 方法需要接收的是字符串
  // 所以我们在这里需要把 data 二进制数据转为 字符串 才可以给模板引擎使用
  var ret = template.render(data.toString(), {
    name: 'Jack',
    age: 18,
    province: '北京市',
    hobbies: [
      '写代码',
      '唱歌',
      '打游戏'
    ],
    title: '个人信息'
  })

  console.log(ret)
})

```

---

### nodemon(让代码修改完直接重启)

> 作用就是让代码修改完可以自动重启
>
> 这是一个第三方命令行工具 他是基于nodejs 开发的 要独立安装

1. *安装*

```shell
npm i nodemon -g //在全局安装
nodemon --version //可以看nodemon的版本 就可以判断有没有安装成功
```

2. 使用

```shell
//在启动时服务时 直接用nodemon 来启动即可
node app.js 换成 nodemon app.js 就可以了
nodemon会监视文件的变化  当文件变化的时候 会自动重启服务器
```

---



### MD5 加密(blueimp-md5)



## [**Express(express)!!!!!!!!!!!!!!!!!!!!** ](http://www.expressjs.com.cn/)

---

- express是一个 基于 node.js平台 `快速的` `开放的` `极简的` web开发框架
- 提供了一套强大的api

---

### 使用express的小demo

```javascript
//0. 安装
// 1. 引包
var express = require('express')

// 2. 创建你服务器应用程序
//    也就是原来的 http.createServer
var app = express()


// 在 Express 中开放资源就是一个 API 的事儿
// 公开指定目录
// 只要这样做了,你就可以直接通过 /public/xx 的方式访问 public 目录中的所有资源了
app.use('/public/', express.static('./public/'))
app.use('/static/', express.static('./static/'))
app.use('/node_modules/', express.static('./node_modules/'))

// 模板引擎,在 Express 也是一个 API 的事儿

// 得到路径
// 一个一个的判断
// 以前的代码很丑

app.get('/about', function (req, res) {
  // 在 Express 中可以直接 req.query 来获取查询字符串参数
  console.log(req.query)
  res.send('你好,我是 Express!')
})

app.get('/pinglun', function (req, res) {
  // req.query
  // 在 Express 中使用模板引擎有更好的方式:res.render('文件名, {模板对象})
  // 可以自己尝试去看 art-template 官方文档:如何让 art-template 结合 Express 来使用
})

// 当服务器收到 get 请求 / 的时候,执行回调处理函数
//第一个参数时请求路径 不包括参数的
app.get('/', function (req, res) {
    // `` 是模板字符串 内容支持换行 和 解析变量 不过变量要${变量名} 使用 es6的语法
  res.send(`
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
<body>
  <h1>hello Express!你好</h1>
</body>
</html>
`)
})

// 相当于 server.listen
app.listen(3000, function () {
  console.log('app is running at port 3000.')
})
```

- req.path 为请求的路径
- req.query  直接 req.query 来获取查询字符串参数( `get请求` ) 返回的是一个对象
- res.send('字符串')  发送响应体
- res.redirect('') 用来重定向url

---

### express中获取get请求参数

- req.query  直接 req.query 来获取查询字符串参数( `get请求` ) 返回的是一个对象

---



### express中获取post请求参数

> 一个第三方模块 包

**需要使用到[中间件](http://www.expressjs.com.cn/resources/middleware.html)   [body-parser](http://www.expressjs.com.cn/en/r ... re/body-parser.html) **

1. *安装*

```shell
npm i body-parser -s
```

2. *配置*

```javascript
var express = require('express')
var bodyParser = require('body-parser')

var app = express()
// 配置body-parser
// 添加这个配置 会让req 的属性多出一个body 里面存放的就是 post请求的数据 是一个对象
// 直接req.body 获取
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json())
```

3. *使用*

```javascript
app.use(function (req, res) {
  res.setHeader('Content-Type', 'text/plain')
  res.write('you posted:\n')
  res.end(JSON.stringify(req.body, null, 2))
})
//以上都是官网示例代码
```

---



### express中使用 [art-template](http://aui.github.io/art-template/zh-cn/)

> express中使用art- template 首先要安装 art-template 和 express-art-template
>
> 要有相关配置才能正常使用 详细如下
>
> 核心方法 res.render('index.html',{模板里写的对象:要替换的对象})

1. *安装*

```shell
npm i art-template -s //安装art-template 安装这个是因为 下面那个还是依赖的这个
npm i express-art-template -s //安装 express-art- template
```

2. *配置*

```javascript
var express = require('express');
var app = express();
//配置art-template
//第一个参数 是 解析这种扩展名的 就使用 art-template模板引擎
app.engine('art', require('express-art-template'));
//如果想改变 render 第一个参数 页面的默认所在目录views 用下面这条代码改
app.set('views',你想要改的路径);
```

3. *使用*

```javascript
app.get('/', function (req, res) {
    //不配置 express-art-template 是没有render这个方法的
    res.render('index.art', {
        user: {
            name: 'aui',
            tags: ['art', 'template', 'nodejs']
        }
    });
});
```



---



### express中的静态资源服务

**使用**

> ```javascript
> var express = require('express')
> var app = express()
> //公开public目录 和 node_moudle目录
> app.use('/public/',express.static('./public/'))
> app.use('/node_modules/', express.static('./node_modules/'))
>
> ```

- 小注意的点
  + 上面代码块中 app.use()的第一个参数 才是 你访问的时候具体写的路径
    + 推荐写成和要公开目录一样的名字 一目了然
  + 第二个参数就是要公开的目录路径
  + 如果只写一个参数的话 那就是可以省略/public/(示范而已)不写

---

### express中路由

> 就是监听 url 又可以分为get post ..请求来分别监听

- 将原来的写在入口模块(app.js)中的 `app.get()app.post()`单独拿出来 作为一个路由模块(router.js)单独存在
- 因为入口模块(`app.js`)职责主要是
  - 创建服务
  - 做一些服务相关配置
    - 模板引擎啊(template....)
    - body-parser(解析表单 post请求)
    - 提供静态资源服务啊(app.use('/public/',express.static('./public/'))
    - .......
  - 挂载 路由
  - 监听端口 并启动服务
- 而路由模块职责(`router.js`)主要是
  - 处理路由
  - 根据不同的请求方式(get/post) 请求路径设置相应的请求函数(一般都是封装起来的)
  - 划分模块还是为了提高 开发效率 增强代码的可维护性

---



### express中使用session





## require 相关

### require 的一些小说法

- require 是一个方法

- 它的作用就是用来加载模块的

    - require 方法有两个作用:

           1.  加载文件模块并执行里面的代码
           2.  拿到被加载文件模块导出的接口对象

                 在每个文件模块中都提供了一个对象:`exports`
                ` exports` 默认是一个空对象
                 你要做的就是把所有需要被外部访问的成员挂载到这个 `exports` 对象中

- 在 Node 中,模块有三种:
    + 具名的核心模块,例如 fs、http
    + 用户自己编写的文件模块
      * 相对路径必须加 ./
      * 可以省略后缀名
      * 相对路径中的 ./ 不能省略,否则报错
    -在 Node 中,没有全局作用域,只有模块作用域
    + 外部访问不到内部
    + 内部也访问不到外部
    + 默认都是封闭的

- 既然是模块作用域,那如何让模块与模块之间进行通信

  + 有时候,我们加载文件模块的目的不是为了简简单单的执行里面的代码,更重要是为了使用里面的某个成员

---





### exports 和 moudle.exports

- 模块中导出多个成员和导出单个成员
- exports 和 module.exports 的区别
  + 每个模块中都有一个 module 对象
  + module 对象中有一个 exports 对象
  + 我们可以把需要导出的成员都挂载到 module.exports 接口对象中
  + 也就是:`moudle.exports.xxx = xxx` 的方式
  + 但是每次都 `moudle.exports.xxx = xxx` 很麻烦,点儿的太多了
  + 所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:`exports`
  + `exports === module.exports` 结果为  `true`s
  + 所以对于:`moudle.exports.xxx = xxx` 的方式 完全可以:`expots.xxx = xxx`
  + **当一个模块需要导出单个成员的时候,这个时候必须使用:`module.exports = xxx` 的方式**
  + 不要使用 `exports = xxx` 不管用
  + 因为每个模块 最终 向外  `return` 的是 `module.exports`
  + 而 `exports` 只是 `module.exports` 的一个引用
  + 所以即便你为 `exports = xx` 重新赋值,也不会影响 `module.exports`
  + 但是有一种赋值方式比较特殊:`exports = module.exports` 这个用来重新建立引用关系的
  + 之所以让大家明白这个道理,是希望可以更灵活的去用它
- **总之记住模块中 最后return 的是moule.exports **

### require加载规则
#### 优先从缓存加载

- 比如在a.js中 引入b.js  再在b.js中引入 c.js   这时 再在a.js中引入c.js 那么这时系统不会再加载 c.js  这里 是引入时为了拿到 c.js中`exports`挂载的对象

#### 自定义模块加载规则

....

#### 系统模块加载规则

...

#### 第三方模块加载规则

...



## 客户端渲染 和 服务端渲染

### 客户端渲染

![](G:\web前端资料\14Nodejs教程精讲(7天+5天赠送)\nodejs资料(7天)\02\code\客户端渲染.png)

### 服务端渲染

![](G:\web前端资料\14Nodejs教程精讲(7天+5天赠送)\nodejs资料(7天)\02\code\服务端渲染.png)

+ 说白了就是在服务端使用模板引擎
+ 模板引擎最早诞生于服务端,后来才发展到了前端

### 服务端渲染和客户端渲染区别

- 服务端渲染和客户端渲染的区别

  + 客户端渲染不利于 SEO 搜索引擎优化

  + 服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的

  + 所以你会发现真正的网站既不是纯异步也不是纯服务端渲染出来的

  + 而是两者结合来做的

  + 例如京东的商品列表就采用的是服务端渲染,目的了为了 SEO 搜索引擎优化

  + 而它的商品评论列表为了用户体验,而且也不需要 SEO 优化,所以采用是客户端渲染

---



## MongoDB

> [参考教程](http://www.runoob.com/mongodb/mongodb-tutorial.html)



## 单线程

- 缺点
  - 无法利用多核cpu
  - 一个用户造成线程崩溃,真个服务器都会崩溃
  - 大量的计算占用cpu导致无法继续调用异步IO
- 优点
  - 操作系统完全不在有线程创建,销毁的时间开销
  - 减少的内存的开销,操作系统饿内存换页
  - 不再向多线程编程一样处处在意状态的同步问题
  - 一个8G的内存服务器,可以同时处理超过4w用户的连接

[**摘自**](https://blog.csdn.net/lmj170/article/details/79482310)

1 个回复

倒序浏览
奶总什么时候出品naimao.js框架?
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马