Node大綱

Node大綱

目錄

  • 1 day

    • 基本介紹
    • 環境配置(node nvm,cnpm)
    • REPL 環境(命令行) 運行js代碼
    • js文件執行
    • nodemon實時監聽
    • 模塊/包與commonjs 規範
      • 內置
      • 第三方
      • 自定義
    • 內置模塊詳解
      • Url
        1. url 介紹
        2. parse
        3. format
      • Query String
        1. parse
        2. stringfly
        3. escape
        4. unescape
      • Http(爬蟲)
        1. get
        2. requst
        3. cheerio
      • Event
      • Fs 文件操做
      • Stream
  • 2dayjavascript

    • 服務器代理跨域原理
    • nodejs建立後端路由
    • nodejs參數
    • node中的異步處理( 前端異步流程工具 )
    • npmscript
    • scocket 實時通訊
      • net
      • websocket
      • socket.io
  • 做業:php

    1. 實現聊天室
  • 3dayhtml

    • express基本使用
    • express 路由
    • express 經常使用插件
    • ejs 模板使用
    • 搭建web服務器(靜態路徑)
    • 搭建api服務
    • api測試工具 postman
    • 做業:
      • 實現文件系統版註冊登陸
  • 4day前端

    • mongodb 環境配置安裝vue

    • mongoose 操做mongod數據庫java

    • 經常使用的服務器緩存redisnode

    • 自動化測試react

  • 5daylinux

    • token 驗證
    • cookie+session 用戶鑑權
    • 圖片上傳實現
    • jwt+驗證碼實現註冊登陸

Node 簡介

客戶端的JavaScript是怎樣的

  • 什麼是 JavaScript?
    +是一個腳本語言
    +運行在瀏覽器(瀏覽器的js解析內核 v8)
    +實現用戶的交互 (interactive)
    • 變量 賦值 循環 邏輯 判斷 分支 對象 函數。。。。
    • dom 操做
    • bom 操做
    • ajax
  • JavaScript 的運行環境?
    +瀏覽器內核解析內核 es6
  • 瀏覽器中的 JavaScript 能夠作什麼?git

  • 瀏覽器中的 JavaScript 不能夠作什麼?(不安全)
    +訪問數據庫
    +不能對文件進行操做
    +對os 進行操做
    +緣由 是不安全 和瀏覽器運行機制有關

  • 在開發人員能力相同的狀況下編程語言的能力取決於什麼?

    +cordova hbuilder 平臺 platform
    +java java虛擬機 (運行平臺)
    +php php虛擬機
    +c# .net framework mono
    +js 解析內核 chrome v8

  • JavaScript 只能夠運行在瀏覽器中嗎?
    +不是

爲何是JavaScript

  • node js 不是由於js 產生的
  • node 選擇了js
  • Ryan dahl
  • 2009 2 月份 node有想法
  • 2009 5 月份 githup 開源
  • 2009 11月份 jsconf 講解推廣node
  • 2010年末 被xxx公司收購
  • 2018 發佈有重大bug
  • npm ( npm 最大的開源 , 包管理器 ) https://www.npmjs.com/
  • github 世界上最大的同性交友網站( github.com) 碼雲( gitee.com)

what is node ?

  • Node.js 是一個基於Chrome V8 引擎的JavaScript運行環境 王者

  • Node.js使用了一個事件驅動、非阻塞式I/O的模型,使其輕量又高效

    • 事件驅動: 任務執行,發佈者,訂閱者,事件驅動 ( on emit )
    • 非阻塞: 執行某一個任務的同時也能夠執行其餘任務
    • 阻塞: 執行某一個任務,這個任務若是沒有執行完成,其餘任務必須等待
      • 同步:
      • 異步
    • I/O: 輸入/輸出( 數據庫操做,文件系統操做等 )
      • 非阻塞I/O模型: 當咱們使用Node.js來實現數據庫操做、文件系統等操做時,要進行的異步操做,異步操做的核心傳統實現方式就是回調函數
  • Node.js的包管理工具npm,是全球最大的開源庫生態系統

    • 第三方: 國外的

    • 建議: 切換國內的, 淘寶國內鏡像源

      • nrm

      • 安裝cnpm

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

        查看是否cnpm安裝成功

        cnpm -v

  • 官網 http://nodejs.cn/

  • npm 插件官網:https://www.npmjs.com/

環境配置

Node的安裝

  • 安裝包安裝

    • 官網下載對應的安裝包
    • 一路next
  • nvm安裝(有一個相似的工具:nvm)

    • Node Version Manager(Node版本管理工具)

    • 因爲之後的開發工做可能會在多個Node版本中測試,並且Node的版本也比較多,因此須要這麼款工具來管理
    • 默認安裝結束以後,默認路徑: C:\Users\xxx\AppData\Roaming\nvm

      nvm安裝教程博客:https://blog.csdn.net/qq_32682137/article/details/82684898

    • 問題: 若是有的同窗,任意目錄不能使用nvm,只有在nvm安裝目錄下才能使用,那麼就是環境變量有問題?

      • 在高級環境變量中的系統變量中建立兩個變量

        1. NVM_HOME
          變量名: NVM_HOME   變量值: nvm安裝目錄路徑
        2. NVM_SYMLINK
          變量名: NVM_SYMLINK 變量值: Node.js的安裝目錄
      • 在系統變量的path路徑中將上面建立的變量引用進來

        ;%NVM_HOME%%NVM_SYMLINK%添加到系統變量  pth路徑的後面

        切記: 不要將path路徑刪除了

      • nvm使用

        nvm list  列出當前電腦中全部的Node.js的版本
        nvm install version  安裝某一個版本的Node.js , 
          舉例: 安裝10.12.0版本        nvm install 10.12.0
        nvm use version 切換某一個Node.js版本
        
          切換後切記: 要確認Node運行十分正常
              node -v 
              npm -v
              若是以上二者輸出正常,那麼久切換成功了
              若是不正常呢?換版本下載安裝( 必須在8.9+ 以上)

相關版本

  • node版本常識
    • 偶數版本爲穩定版 (0.6.x ,0.8.x ,0.10.x)
    • 奇數版本爲非穩定版(0.7.x ,0.9.x ,0.11.x)
    • LTS(Long Term Support)
    • LTS和Current區別
  • 操做方式:
    • 從新下載最新的安裝包;
    • 覆蓋安裝便可;
  • 問題:
    • 之前版本安裝的不少全局的工具包須要從新安裝
    • 沒法回滾到以前的版本
    • 沒法在多個版本之間切換(不少時候咱們要使用特定版本)

Windows下經常使用的命令行操做

  • 切換當前目錄(change directory):cd
  • 建立目錄(make directory):mkdir
  • 查看當前目錄列表(directory):dir
    • 別名:ls(list)
  • 清空當前控制檯:cls
    • 別名:clear
  • 刪除文件:del
    • 別名:rm

注意:全部別名必須在新版本的 PowerShell (linux系統)中使用

電腦:

​ cmd裏面用的叫作 DOS命令

​ cmd終端喚醒: win鍵 + R , 輸入cmd 回車

​ mkdir 建立目錄

​ dir 列出當前目錄的列表

​ cls 清空終端命令

​ del 刪除某一個文件

​ git / powershell 用的是linux命令

​ mkdir 建立目錄

​ ls 查看當前目錄列表

​ clear 清空當前控制檯

​ rm -rf 文件名稱 刪除某一個文件或是目錄

​ 兩種類型的命令中, cd是一個意思

常見問題

  • 環境變量丟失

  • 部分電腦安裝完畢以後沒有環境變量須要手動配置
  • Windows中環境變量分爲系統變量和用戶變量
  • 環境變量的變量名是不區分大小寫的
  • PATH 變量:只要添加到 PATH 變量中的路徑,均可以在任何目錄下
  • 目的能夠在任何地方調起node命令

Node.js實時監聽( 自動刷新 )

藉助第三方工具實現:

​ nodemon 【 推薦

​ cnpm i nodemon -g

​ nodemon 文件名稱

​ supervisor

​ cnpm i supervisor -g

​ supervisor 文件名稱

模塊,包 commonjs

commonjs規範

前端模塊化:AMD,CMD,Commonjs

Node 應用由模塊組成,採用 CommonJS 模塊規範。

定義module

每一個文件就是一個模塊,有本身的做用域。在一個文件裏面定義的變量、函數、類,都是私有的,對其餘文件不可見。

暴露接口

CommonJS規範規定,每一個模塊內部,module變量表明當前模塊。這個變量是一個對象,它的exports屬性(即module.exports)是對外的接口。加載某個模塊,實際上是加載該模塊的module.exports屬性。

var x = 5;
    var addX = function (value) {
      return value + x;
    };
    module.exports.x = x;
    module.exports.addX = addX;
引用

require方法用於加載模塊。

var example = require('./example.js');
    console.log(example.x); // 5
    console.log(example.addX(1)); // 6

模塊的分類

  • 內置模塊
const process = require('process')
    const path = require('path')
    console.log(process.version)
    console.log(path.resolve('../'))
  • 第三方模塊
const request=require("request");
    console.log(request)
    request.get('http://api.douban.com/v2/movie/in_theaters', (err, response, body) => {
      if (!err) {
        // console.log(body);
        console.log(JSON.parse(body))
      } else {
        console.log(err);
      }
    })
  • 自定義模塊

npm 使用入門

官網:https://www.npmjs.com/

安裝:無需安裝

查看當前版本:

$ npm -v

更新:

$ npm install npm@latest -g

初始化工程

$ npm init

 $ npm init --yes 默認配置

安裝包

使用npm install會讀取package.json文件來安裝模塊。安裝的模塊分爲兩類
dependencies和devDependencies,分別對應生產環境須要的安裝包和開發環境須要的安裝包。

$ npm install

 $ npm install <package_name> 

 $ npm install <package_name> --save

 $ npm install <package_name> --save-dev

更新模塊

$ npm update

卸載模塊

$ npm uninstall <package_name>

 $ npm uninstall --save lodash

配置npm源

  • 臨時使用, 安裝包的時候經過--registry參數便可

    $ npm install express --registry https://registry.npm.taobao.org

  • 全局使用

    $ npm config set registry https://registry.npm.taobao.org
      // 配置後可經過下面方式來驗證是否成功
      npm config get registry
      // 或
      npm info express
  • cnpm 使用

    // 安裝cnpm
        npm install -g cnpm --registry=https://registry.npm.taobao.org
    
        // 使用cnpm安裝包
        cnpm install express

經常使用的內置模塊

node 經常使用內置api

(1) URL 網址解析
解析URL相關網址信息
url.parse(urlString[, parseQueryString[, slashesDenoteHost]])
url.format(urlObject)
url.resolve(from, to)

(2) QueryString 參數處理
querystring.escape(str)
querystring.unescape(str)
querystring.parse(str[, sep[, eq[, options]]])
querystring.stringify(obj[, sep[, eq[, options]]])

(3) HTTP 模塊概要
http.createServer([options][, requestListener])
http.get(options[, callback])
簡易的爬蟲
代理跨域處理

(4) 事件 events 模塊

(5) 文件fs模塊
打印目錄樹

(6) Stream 流模塊
歌詞播放
音樂下載

(8) request 方法

二、Node.js 基礎應用
一、應用 HTTP 模塊編寫一個小爬蟲工具

(1) 利用爬蟲獲取「拉勾網」首頁列表數據

(2) 經過 npm 安裝 cheerio 模塊得到數據
二、後端表單的提交
要求:

(1) 應用 request post 模擬提交表單

文件讀取

Node中文件讀取的方式主要有:

fs.readFile(file[, options], callback(error, data))

fs.readFile('c:\\demo\1.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

fs.readFileSync(file[, options])

try {
  const data = fs.readFileSync('c:\\demo\1.txt', 'utf8');
  console.log(data);
} catch(e) {
  // 文件不存在,或者權限錯誤
  throw e;
}

fs.createReadStream(path[, options])

const stream = fs.createReadStream('c:\\demo\1.txt');
let data = ''
stream.on('data', (trunk) => {
  data += trunk;
});
stream.on('end', () => {
  console.log(data);
});

因爲Windows平臺下默認文件編碼是GBK,在Node中不支持,能夠經過iconv-lite解決

Readline模塊逐行讀取文本內容

const readline = require('readline');
const fs = require('fs');

const rl = readline.createInterface({
  input: fs.createReadStream('sample.txt')
});

rl.on('line', (line) => {
  console.log('Line from file:', line);
});

文件寫入

Node中文件寫入的方式主要有:

fs.writeFile(file, data[, options], callback(error))

fs.writeFile('c:\\demo\a.txt', new Date(), (error) => {
  console.log(error);
});

fs.writeFileSync(file, data[, options])

try {
  fs.writeFileSync('c:\\demo\a.txt', new Date());
} catch (error) {
  // 文件夾不存在,或者權限錯誤
  console.log(error);
}

fs.createWriteStream(path[,option])

var streamWriter = fs.createWriteStream('c:\\demo\a.txt');
setInterval(() => {
  streamWriter.write(`${new Date}\n`, (error) => {
    console.log(error);
  });
}, 1000);

node中的異步操做

  • fs模塊對文件的幾乎全部操做都有同步和異步兩種形式
  • 例如:readFile() 和 readFileSync()
  • 區別:
    • 同步調用會阻塞代碼的執行,異步則不會
    • 異步調用會將讀取任務下達到任務隊列,直到任務執行完成纔會回調
    • 異常處理方面,同步必須使用 try catch 方式,異步能夠經過回調函數的第一個參數
console.time('sync');
try {
  var data = fs.readFileSync(path.join('C:\\Users\\iceStone\\Downloads', 'H.mp4'));
  // console.log(data);
} catch (error) {
  throw error;
}
console.timeEnd('sync');

console.time('async');
fs.readFile(path.join('C:\\Users\\iceStone\\Downloads', 'H.mp4'), (error, data) => {
  if (error) throw error;
  // console.log(data);
});
console.timeEnd('async');
promise 對象的使用

參考資料:JavaScript Promise迷你書

  • what is Promise *
    Promise是抽象異步處理對象以及對其進行各類操做的組件。Promise並非從JavaScript中發祥的概念。
    Promise最初被提出是在 E語言中, 它是基於並列/並行處理設計的一種編程語言。
    如今JavaScript也擁有了這種特性,這就是JavaScript Promise

使用了回調函數的異步處理

----
getAsync("fileA.txt", function(error, result){
    if(error){// 取得失敗時的處理
        throw error;
    }
    // 取得成功時的處理
});
----
<1> 傳給回調函數的參數爲(error對象, 執行結果)錯誤優先處理

使用了回調函數的異步處理

----
var promise = getAsyncPromise("fileA.txt"); 
promise.then(function(result){
    // 獲取文件內容成功時的處理
}).catch(function(error){
    // 獲取文件內容失敗時的處理
});
----
<1> 返回promise對象
  • 建立Promise對象 *
var promise = new Promise(function(resolve, reject) {
    // 異步處理
    // 處理結束後、調用resolve 或 reject
    resolve('成功處理')
    reject('錯誤處理')
});
  • 使用實例 *
  1. 建立一個priomise 對象並返回new Promise(fn)
  2. 在fn 中指定異步等處理
    • 處理結果正常的話,調用resolve(處理結果值)
    • 處理結果錯誤的話,調用 reject(Error對象)
function asyncFunction() {
    
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve('Async Hello world');
        }, 16);
    });
}

asyncFunction().then(function (value) {
    console.log(value);    // => 'Async Hello world'
}).catch(function (error) {
    console.log(error);
});
  • Promise的狀態

用new Promise 實例化的promise對象有如下三個狀態。

  • "has-resolution" - Fulfilled resolve(成功)時。
  • "has-rejection" - Rejected reject(失敗)時
  • "unresolved" - Pending 既不是resolve也不是reject的狀態。也就是promise對象剛被建立後的初始化狀態等

promise對象的狀態,從Pending轉換爲Fulfilled或Rejected以後, 這個promise對象的狀態就不會再發生任何變化。

也就是說,Promise與Event等不一樣,在.then 後執行的函數能夠確定地說只會被調用一次。

另外,Fulfilled和Rejected這兩個中的任一狀態均可以表示爲Settled(不變的)。

Settled
resolve(成功) 或 reject(失敗)。

從Pending和Settled的對稱關係來看,Promise狀態的種類/遷移是很是簡單易懂的。

當promise的對象狀態發生變化時,用.then 來定義只會被調用一次的函數。

路徑模塊

在文件操做的過程當中,都必須使用物理路徑(絕對路徑),path模塊提供了一系列與路徑相關的 API

console.log('join用於拼接多個路徑部分,並轉化爲正常格式');
const temp = path.join(__dirname, '..', 'lyrics', './友誼之光.lrc');
console.log(temp);

console.log('獲取路徑中的文件名');
console.log(path.basename(temp));

console.log('獲取路徑中的文件名並排除擴展名');
console.log(path.basename(temp, '.lrc'));

console.log('====================================');

console.log('獲取不一樣操做系統的路徑分隔符');
console.log(process.platform + '的分隔符爲 ' + path.delimiter);

console.log('通常用於分割環境變量');
console.log(process.env.PATH.split(path.delimiter));

console.log('====================================');

console.log('獲取一個路徑中的目錄部分');
console.log(path.dirname(temp));

console.log('====================================');

console.log('獲取一個路徑中最後的擴展名');
console.log(path.extname(temp));

console.log('====================================');

console.log('將一個路徑解析成一個對象的形式');
const pathObject = path.parse(temp);
console.log(pathObject);

console.log('====================================');

console.log('將一個路徑對象再轉換爲一個字符串的形式');
// pathObject.name = '我終於失去了你';
pathObject.base = '我終於失去了你.lrc';
console.log(pathObject);

console.log(path.format(pathObject));

console.log('====================================');

console.log('獲取一個路徑是否是絕對路徑');
console.log(path.isAbsolute(temp));
console.log(path.isAbsolute('../lyrics/愛的代價.lrc'));

console.log('====================================');

console.log('將一個路徑轉換爲當前系統默認的標準格式,並解析其中的./和../');
console.log(path.normalize('c:/develop/demo\\hello/../world/./a.txt'));

console.log('====================================');

console.log('獲取第二個路徑相對第一個路徑的相對路徑');
console.log(path.relative(__dirname, temp));

console.log('====================================');

console.log('以相似命令行cd命令的方式拼接路徑');
console.log(path.resolve(temp, 'c:/', './develop', '../application'));

console.log('====================================');

console.log('獲取不一樣平臺中路徑的分隔符(默認)');
console.log(path.sep);

console.log('====================================');

console.log('容許在任意平臺下以WIN32的方法調用PATH對象');
// console.log(path.win32);
console.log(path === path.win32);

console.log('====================================');

console.log('容許在任意平臺下以POSIX的方法調用PATH對象');
console.log(path === path.posix);

express


官網:http://www.expressjs.com.cn/

express 環境搭建

安裝

$ npm install express --save

快速開始

const express = require('express')
    const app = express()
    app.get('/', (req, res) => res.send('Hello World!'))
    app.listen(3000, () => console.log('Example app listening on port 3000!'))

express 路由配置

let express=require('express')
let router=express.Router()
// 該路由使用的中間件
router.use((req,res,next)=>{
     next()
});
// 定義網站主頁的路由
router.post('/addFood', function(req, res) {
    console.log('hahaha')
  // res.send('這裏是admin的登陸');
});
// 定義 about 頁面的路由
router.post('/regist', function(req, res) {
  res.send('這裏是admin的註冊側');
});

module.exports = router;

app.use('/admin',admin)

傳遞數據的獲取

get
req.query
post
req.body
body-parser

設置中文格式
res.set('Content-Type','text/plain,charset=utf8')

請求模擬工具 insomina

靜態資源配置

app.use(express.static('public'))

app.use('/static', express.static('public'))

app.use('/static', express.static(path.join(__dirname, 'public')))

mongod

安裝配置

Mongodb官網下載最新版本的Mongodb下載地址

下載msiwindow安裝包,能夠裝到C盤或者D盤目錄下

配置

因爲我是安裝在D盤的環境下

D:\Program Files (x86)\MongoDB\Server\3.2\bin

因此在bin文件夾下找到mongod.exe命令,而後經過管理員執行mongod --dbpath x路徑x,路徑能夠是任何地方,我這裏選擇在D盤的MongoDB目錄下,固然路徑不要包含特殊的字符串,好比Program Files (x86)也不行

mongod --dbpath D:\mongodb\data\db

image

命令行

通過上面的配置以後,就能夠返回bin目錄下找到mongo.exe命令,並管理員下執行,就能夠出現mongodb的命令行模式

D:\Program Files (x86)\MongoDB\Server\3.2\bin

image

而後就可使用下面的命令來測試了

mongod

db.help()//幫助
db.stats()//統計

顯示數據庫

show dbs

檢查當前選擇的數據庫

db

添加數據庫

數據庫名爲數據庫建立的名字,使用該命令後會默認切換到對應的數據庫,而且在數據庫中添加選項,數據庫信息才顯示,若是默認就有該數據庫,那就是切換到對應的數據庫裏面

use 數據庫名

刪除數據庫

先切換到對應的數據庫,而後再執行db.dropDatabase()刪除該數據庫

use 數據庫名
//switched to db 數據庫名
db.dropDatabase()

顯示集合

用一下命令能夠檢查建立的集合

show collections

添加集合

在建立完數據庫以後,咱們就能夠建立集合

db.createCollection(集合名字name,設置參數options[對象類型])

name是要建立的集合的名稱。 options是一個文檔,用於指定集合的配置

參數 類型 描述
name String 要建立的集合的名稱
options Document (可選)指定有關內存大小和索引的選項
options參數是可選的,所以只須要指定集合的名稱。 如下是可使用的選項列表:

字段 類型 描述
capped Boolean (可選)若是爲true,則啓用封閉的集合。上限集合是固定大小的集合,它在達到其最大大小時自動覆蓋其最舊的條目。 若是指定true,則還須要指定size參數。
autoIndexId Boolean (可選)若是爲true,則在_id字段上自動建立索引。默認值爲false。
size 數字 (可選)指定上限集合的最大大小(以字節爲單位)。 若是capped爲true,那麼還須要指定此字段的值。
max 數字 (可選)指定上限集合中容許的最大文檔數。
因爲option是可選,咱們也能夠不帶配置項建立集合

db.createCollection("mycollection")

刪除集合

db.collection.drop()用於從數據庫中刪除集合

db.集合名.drop()

好比咱們能夠測試如下操做

db.createCollection("wscats")//建立名爲wscats的集合
show collections//顯示該數據庫全部集合   wscats
db.wscats.drop()//刪除名爲wscats的集合

查看文檔

最簡單查看文檔的方法就是find(),會檢索集合中全部的文檔結果

db.集合名.find()

要以格式化的方式顯示結果,可使用pretty()方法。

db.集合名.find().pretty()

1.固值尋找

尋找age集合裏面全部含有屬性值爲wscats的文檔結果,至關於where name = 'wscats'

db.age.find({name:"wscats"})

2.範值尋找

操做 語法 示例 等效語句
相等 {:} db.age.find({"name":"wscats"}).pretty() where name = 'wscats'
小於 {:{$lt:}} db.age.find({"likes":{$lt:50}}).pretty() where likes < 50
小於等於 {:{$lte:}} db.age.find({"likes":{$lte:50}}).pretty() where likes <= 50
大於 {:{$gt:}} db.age.find({"likes":{$gt:50}}).pretty() where likes > 50
大於等於 {:{$gte:}} db.age.find({"likes":{$gte:50}}).pretty() where likes >= 50
不等於 {:{$ne:}} db.age.find({"likes":{$ne:50}}).pretty() where likes != 50

3.AND和OR尋找

AND

在find()方法中,若是經過使用將它們分開傳遞多個鍵,則mongodb將其視爲AND條件。 如下是AND的基本語法

尋找_id爲1而且name爲wscats的全部結果集

db.age.find(
{
   $and: [
      {"_id": 1}, {"name": "wscats"}
   ]
}
)

OR

在要根據OR條件查詢文檔,須要使用$or關鍵字。如下是OR條件的基本語法

尋找name爲corrine或者name爲wscats的全部結果集

db.age.find(
{
   $or: [
      {"name": "corrine"}, {「name「: "wscats"}
   ]
}
)

AND和OR等結合

至關於語句where title = "wscats" OR ( title = "corrine" AND _id < 5)

db.age.find({
$or: [{
 "title": "wscats"
}, {
 $and: [{
   "title": "corrine"
 }, {
   "_id": {
     $lte: 5
   }
 }]
}]
})

插入文檔

文檔的數據結構和JSON基本同樣。
全部存儲在集合中的數據都是BSON格式。
BSON是一種類json的一種二進制形式的存儲格式,簡稱Binary JSON

要將數據插入到mongodb集合中,須要使用mongodb的insert()save()方法。

db.集合名.insert(document)

好比咱們能夠插入如下數據

db.wscats.insert({
_id: 100,
title: 'MongoDB Tutorials', 
description: 'node_tutorials',
by: 'Oaoafly',
url: 'https://github.com/Wscats/node-tutorial',
tags: ['wscat','MongoDB', 'database', 'NoSQL','node'],
num: 100,
})

也能夠支持插入多個,注意傳入的是數組形式

db.wscats.insert([{
_id: 100,
title: ‘Hello’
},{
_id: 101,
title: ‘World’
}])

在插入的文檔中,若是不指定_id參數,那麼mongodb會爲此文檔分配一個惟一的ObjectId
要插入文檔,也可使用db.post.save(document)。若是不在文檔中指定_id,那麼save()方法將與insert()方法同樣自動分配ID的值。若是指定_id,則將以save()方法的形式替換包含**_id**的文檔的所有數據。

db.wscats.save({
_id: 111,
title: 'Oaoafly Wscats', 
})

更新文檔

1.update()方法

尋找第一條title爲wscats的值,而且更新值title爲corrine和age爲12

db.age.update({
'title': 'wscats'
}, {
$set: {
 'title': 'corrine',
 'age': 12
}
})

默認狀況下,mongodb只會更新一個文檔。要更新多個文檔,須要將參數multi設置爲true,還能夠配合find方法裏面的各類複雜條件判斷來篩選結果,而後更新多個文檔

尋找全部title爲wscats的值,而且更新值title爲corrine和age爲12

db.age.update({
'title': 'wscats'
}, {
$set: {
 'title': 'corrine',
 'age': 12
}
}, {
multi: true
})

2.save()方法

_id主鍵爲3的文檔,覆蓋新的值,注意_id爲必傳

db.age.save({
'_id':3,
'title': 'wscats'
})

刪除文檔

刪除主鍵_id爲3的文檔,默認是刪除多條

db.age.remove({
'_id':3
})

建議在執行remove()函數前先執行find()命令來判斷執行的條件是否正確

若是你只想刪除第一條找到的記錄能夠設置justOne爲1,以下所示

db.age.remove({...},1)

所有刪除

db.age.remove({})

Limit與Skip方法

Limit

若是你須要在mongodb中讀取指定數量的數據記錄,可使用mongodb的Limit方法,limit()方法接受一個數字參數,該參數指定從mongodb中讀取的記錄條數。

db.age.find().limit(數量)

Skip

咱們除了可使用limit()方法來讀取指定數量的數據外,還可使用skip()方法來跳過指定數量的數據,skip方法一樣接受一個數字參數做爲跳過的記錄條數。

db.age.find().limit(數量).skip(數量)
//skip()方法默認值爲0

因此咱們在實現分頁的時候就能夠用limit來限制每頁多少條數據(通常固定一個值),用skip來決定顯示第幾頁(一個有規律變更的值)

排序

在mongodb中使用使用sort()方法對數據進行排序,sort()方法能夠經過參數指定排序的字段,並使用1和-1來指定排序的方式,其中1爲升序排列,而-1是用於降序排列。

1 升序排列
-1 降序排列

db.集合名.find().sort({鍵值(屬性值):1})

age集合表從新根據_id主鍵進行降序排列

db.age.find().sort({
"_id": -1
})

Node.js鏈接

安裝mongodb的模塊

npm install mongodb

1.鏈接數據庫

var MongoClient = require('mongodb').MongoClient;
//結尾是選擇數據庫名
var DB_CONN_STR = 'mongodb://localhost:27017/wscats';
MongoClient.connect(DB_CONN_STR, function(err, db) {
console.log("鏈接成功!");
});

2.查詢數據

注意查詢回來的結果須要toArray來遍歷處理

var MongoClient = require('mongodb').MongoClient;
var DB_CONN_STR = 'mongodb://localhost:27017/wscats';

MongoClient.connect(DB_CONN_STR, function(err, db) {
console.log("鏈接成功!");
//選中age集合,並用find方法把結果集拿回來進行處理
db.collection("age").find({title: "cba"}).toArray(function(err, result) {
 if (err) {
   console.log('Error:' + err);
   return;
 }
 console.log(result);
});
});

通過測試,讀取大於100條的時候會出現報錯官網解釋,能夠嘗試用forEach代替

db.collection('pokemon').find({})
.forEach(function(item){
   console.log(item)
})

查詢ID

查詢自動生成的ObjectId

var ObjectId = require('mongodb').ObjectId;
let _id = ObjectId("5bcae50ed1f2c2f5e4e1a76a");
db.collection('xxx').find({
 "_id": _id
}).forEach(function (item) {
 console.log(item)
})

3.插入數據

insert函數第一個參數是須要插入的值(能夠一個也能夠多個),第二個參數是接受一個回調函數,當值插入成功後回返回插入值得一些關鍵信息,好比_id

var MongoClient = require('mongodb').MongoClient;
var DB_CONN_STR = 'mongodb://localhost:27017/wscats';

MongoClient.connect(DB_CONN_STR, function(err, db) {
console.log("鏈接成功!");
  const db = client.db("demo");
db.collection("age").insert([
 { 
   title: "插入的值A"
 }, {
   title: "插入的值B"
 }
], function(err, result) {
 if (err) {
   console.log('Error:' + err);
   return;
 }
 console.log(result)
})
});

4.更新數據

注意若是不加$set就是徹底替換原來的那份(沒有設置的屬性值將會丟失),加上$set則只是更新對應的屬性值,其他不作改變

var MongoClient = require('mongodb').MongoClient;
var DB_CONN_STR = 'mongodb://localhost:27017/wscats';

MongoClient.connect(DB_CONN_STR, function(err, db) {
console.log("鏈接成功!");
db.collection("age").update({
 "_id": 1
}, {
 $set: {
   title: "你好,世界",
   skill: "js"
 }
}, function(err, result) {
 if (err) {
   console.log('Error:' + err);
   return;
 }
 //console.log(result);
});
});

5.刪除數據

var MongoClient = require('mongodb').MongoClient;
var DB_CONN_STR = 'mongodb://localhost:27017/wscats';

MongoClient.connect(DB_CONN_STR, function(err, db) {
console.log("鏈接成功!");
db.collection("age").remove({
 "_id": 1
}, function(err, result) {
 if (err) {
   console.log('Error:' + err);
   return;
 }
 //console.log(result);
 //關閉數據庫
 db.close();
});
});

6.關閉數據庫

db.close();

封裝自定義模塊

新建mongo.js寫入如下代碼,封裝自定義模塊,方便其餘路由複用,注意assert是node自帶的斷言模塊,用於測試代碼

參考

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
const url = 'mongodb://localhost:27017';
const dbName = 'shop';
function query(callback) {
  MongoClient.connect(url, function(err, client) {
      assert.equal(null, err);
      console.log("Connected successfully to server");
      const db = client.db(dbName);
      callback(db);
      client.close();
  });
}
module.exports = {
  query
}

在路由文件中引入和使用

var mongo = require('./mongo.js')
router.post('/addproduct', function(req, res, next) {
  mongo.query(function(db) {
      db.collection("product").insertMany([req.body], function(err, result) {
          console.log("Inserted 1 document into the collection");
          res.send('respond with a resource');
      });
  })
});

mongoose

  1. 下載mongoose
npm install mongoose --save
  1. 鏈接數據庫
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/1823');
var db = mongoose.connection;// 獲取鏈接對象進行監聽
db.on('error',(err)=>{
    console.log('鏈接錯誤')
});
db.on('open', function() {
  console.log('鏈接ok')
});
  1. 建立schema對象
var UserSchema = new mongoose.Schema({
    name: String,
    pass: String,
    test:String
  });
  1. 將schema轉化爲數據模型
let user = mongoose.model('user', UserSchema); //參數1 是集合的名字 與數據模型關聯的schema對象
  1. 經過數據模型執行查詢操做

mongoose

可視化

Socket

  • 實時刷新(蠟燭圖)
  • 推送服務

socket.io

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>socket.io</title>
  <script src="socket.io.js" charset="utf-8"></script>
</head>
<body>
  <h1>gp6 交流區</h1>
  <div id="content" name="name" style="overflow-y: scroll; width: 400px; height: 300px; border: solid 1px #000"></div>
  <br />
  <div>
    <input type="text" id="msg" style="width: 200px;">
  </div>
  <button id="submit">提交</button>
  <script>
    var socket = io.connect('http://10.9.164.98:8081');
    const content = document.getElementById('content')
    document.querySelector('#submit')
      .addEventListener('click', function () {
        var msg2 = msg.value
        socket.emit('receive', msg2)
        msg.value = ''
        content.innerHTML += msg2 + '<br/>'
      }, false)

      socket.on('message', function(msg){
        content.innerHTML += msg + '<br/>'
      })
  </script>
</body>
</html>

server.js

var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);

app.use(express.static(__dirname + '/client'))

io.on('connection', function (socket) {
  setInterval(function () {
    socket.emit('list', 'abc')
  }, 1000)
  socket.broadcast.emit('list', 'test');
  socket.on('backend', (msg) => {
    console.log(msg);
  })

  socket.on('receive', (msg) => {
    socket.broadcast.emit('message', msg);
  })
});

server.listen(8081, '10.9.164.98');

net模塊

serverCode

const net = require('net')

const server = new net.createServer()

let clients = {}
let clientName = 0

server.on('connection', (client) => {
  client.name = ++clientName
  clients[client.name] = client

  client.on('data', (msg) => {
    // console.log('客戶端傳來:' + msg);
    broadcast(client, msg.toString())
  })

  client.on('error', (e) => {
    console.log('client error' + e);
    client.end()
  })

  client.on('close', (data) => {
    delete clients[client.name]
    console.log(client.name + ' 下線了');
  })
})

function broadcast(client, msg) {
  for (var key in clients) {
    clients[key].write(client.name + ' 說:' + msg)
  }
}

server.listen(9000)

clientCode

var net = require('net')
const readline = require('readline')

var port = 9000
var host = '127.0.0.1'

var socket = new net.Socket()

socket.setEncoding = 'UTF-8'

socket.connect(port, host, () => {
  socket.write('hello.')
})

socket.on('data', (msg) => {
  console.log(msg.toString())
  say()
})

socket.on('error', function (err) {
  console.log('error' + err);
})

socket.on('close', function () {
  console.log('connection closeed');
})

const r1 = readline.createInterface({
  input: process.stdin,
  output: process.stdout
})

function say() {
  r1.question('請輸入:', (inputMsg) => {
    if (inputMsg != 'bye') {
      socket.write(inputMsg + '\n')
    } else {
      socket.destroy()
      r1.close()
    }
  })
}

websocket

const ws = new WebSocket('ws://localhost:8080/')

ws.onopen = () => {
  ws.send('你們好')
}

ws.onmessage = (msg) => {
  const content = document.getElementById('content')
  content.innerHTML += msg.data + '<br/>'
}

ws.onerror = (err) => {
  console.log(err);
}

ws.onclose = () => {
  console.log('closed~');
}
ws.send(msg2)

server.js

const WebSocket = require('ws')
const ws = new WebSocket.Server({ port: 8080 })

let clients = {}
let clientName = 0

ws.on('connection', (client) => {
  client.name = ++clientName
  clients[client.name] = client

  client.on('message', (msg) => {
    broadcast(client, msg)
  })

  client.on('close', () => {
    delete clients[client.name]
    console.log(client.name + ' 離開了~')
  })
})

function broadcast(client, msg) {
  for (var key in clients) {
    clients[key].send(client.name + ' 說:' + msg)
  }
}

SSR 與 SEO

vue 和 react 介紹

項目實戰

api接口

  • RestfulApi 規範
  • 接口文檔的生成(apidoc)
  • 接口請求方式區別

跨域解決

  • cors
  • jsonp
  • proxy

Hui 基本使用

身份驗證

http 請求的無狀態性

JWT

  • 用戶登陸 服務器端產生一個token (加密字符串) 發送給前端
  • 前端將token 進行保存
  • 前端發起數據請求的時候攜帶token
  • 服務端 驗證token 是否合法 若是合法繼續操做 不合法終止操做
  • token 的使用場景 無狀態請求 保持用戶的登陸狀態 第三方登陸(token+auth2.0)
非對稱加密 經過私鑰產生token 經過公鑰解密token
// 1.產生公鑰和私鑰
// 產生私鑰  openssl genrsa -out ./private_key.pem 1024    1024 表明私鑰長度
// 產生公鑰  openssl rsa -in ./private_key.pem -pubout -out ./public_key.pem

 let private_key=fs.readFileSync(path.join(__dirname,'./private_key.pem'))
 let public_key=fs.readFileSync(path.join(__dirname,'./public_key.pem'))
 var token = jwt.sign(palyload, private_key,{ algorithm: 'RS256'});
 console.log(token)
 let  token='eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IueUqOaIt2lkIiwiaWF0IjoxNTUxMTUyNzk1fQ.TI_xDBvObHGAH7EV40WWpQemm5nx077Gdjq-pzDx0NWN5YFd40S7XcLmgoDdYscLM7vMOP0c7z1l83JUixqk7IBjBCU-tMNo_G5_-LGkQjV3vDYq_3TkXTl42lgmFA-EBey7W6W1PgPfYlowyHAyp-07hXaMRevgVkXm2lPEFXo'

  var decoded = jwt.verify(token, public_key);
const jwt=require('jsonwebtoken')
const scrict='sdjfksdjflajflasjflasjflksf'

function creatToken(palyload){
    // 產生token
    palyload.ctime=Date.now()
    return jwt.sign(palyload,scrict)
}
function checkToken(token){
    return  new Promise((resovle,reject)=>{
        jwt.verify(token,scrict,(err,data)=>{
           if(err){ reject('token 驗證失敗')}
           resovle(data)
           })
    })
    
}
module.exports={
    creatToken,checkToken
}

Cookie+Session

const  cookieParse=require('cookie-parser')
const  session = require('express-session')

app.use(session({
    secret: 'hubwizApp', //爲了安全性的考慮設置secret屬性
    cookie: {maxAge: 60 * 1000 * 60 * 24 }, //設置過時時間
    resave: true, // 即便 session 沒有被修改,也保存 session 值,默認爲 true
    saveUninitialized: false, //不管有沒有session cookie,每次請求都設置個session cookie ,默認給個標示爲 connect.sid
}));

登陸成功

req.session.sign = true;
req.session.name = us;

須要驗證的接口判斷是否存在

註銷session

app.get('/out', function(req, res){
    req.session.destroy();
    res.redirect('/');
})

圖片上傳

  1. 安裝multer模塊
npm install multer
  1. 引用模塊
    它是依賴於express的一個模塊
//引用express並配置
var express = require("express");
var app = express();
app.listen(3000);
var multer = require('multer');
/*var upload = multer({
    //若是用這種方法上傳,要手動添加文明名後綴
        //若是用下面配置的代碼,則能夠省略這一句
    dest: 'uploads/'
})*/
  1. 配置
    設置保存文件的地方,並根據上傳的文件名對應文件添加後綴
    能夠經過filename屬性定製文件保存的格式
屬性值 用途
destination 設置資源的保存路徑。注意,若是沒有這個配置項,默認會保存在/tmp/uploads下。此外,路徑須要本身建立
filename 設置資源保存在本地的文件名
var storage = multer.diskStorage({
    //設置上傳後文件路徑,uploads文件夾會自動建立。
    destination: function(req, file, cb) {
        cb(null, './uploads')
    },
    //給上傳文件重命名,獲取添加後綴名
    filename: function(req, file, cb) {
        var fileFormat = (file.originalname).split(".");
        //給圖片加上時間戳格式防止重名名
        //好比把 abc.jpg圖片切割爲數組[abc,jpg],而後用數組長度-1來獲取後綴名
        cb(null, file.fieldname + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1]);
    }
});
var upload = multer({
    storage: storage
});
  1. 接受文件
    upload.single('xxx'),xxx與表單中的name屬性的值對應
    這裏雖然用到post請求,但實際上不須要bodyParser模塊處理
app.post('/upload-single', upload.single('logo'), function(req, res, next) {
    console.log(req.file)
    console.log('文件類型:%s', req.file.mimetype);
    console.log('原始文件名:%s', req.file.originalname);
    console.log((req.file.originalname).split("."))
    console.log('文件大小:%s', req.file.size);
    console.log('文件保存路徑:%s', req.file.path);
    res.send({
        ret_code: '0'
    });
});
  1. 多圖上傳
    多圖上傳只要更改一下地方,前端往file輸入框加多一個multiple="multiple"屬性值,此時就能夠在選圖的時候多選了,固然也能夠並列多個file輸入框(不推薦多個上傳圖片輸入框),這樣體驗會很差
<input type="file" name="logo" multiple="multiple" />

後端也須要相應的改變

app.post('/upload-single', upload.single('logo'), function(req, res, next) {
//upload.single('logo')變爲upload.array('logo', 2),數字表明能夠接受多少張圖片
app.post('/upload-single', upload.array('logo', 2), function(req, res, next) {

若是不想有圖片數量上傳限制,咱們能夠用upload.any()方法

app.post('/upload-single', upload.any(), function(req, res, next) { 
    res.append("Access-Control-Allow-Origin","*");
    res.send({
        wscats_code: '0'
    });
});
  1. 前端部分
  • formData表單提交
<form action="http://localhost:3000/upload-single" method="post" enctype="multipart/form-data">
    <h2>單圖上傳</h2>
    <input type="file" name="logo">
    <input type="submit" value="提交">
</form>
  • formData表單+ajax提交
<form id="uploadForm">
    <p>指定文件名: <input type="text" name="filename" value="" /></p>
    <p>上傳文件: <input type="file" name="logo" /></ p>
    <input type="button" value="上傳" onclick="doUpload()" />
</form>

FormData對象,是可使用一系列的鍵值對來模擬一個完整的表單,而後使用XMLHttpRequest發送這個"表單"

注意點

  • processData設置爲false。由於data值是FormData對象,不須要對數據作處理。
  • <form>標籤添加enctype="multipart/form-data"屬性。
  • cache設置爲false,上傳文件不須要緩存。
  • contentType設置爲false。由於是由<form>表單構造的FormData對象,且已經聲明瞭屬性enctype="multipart/form-data",因此這裏設置爲false

上傳後,服務器端代碼須要使用從查詢參數名爲logo獲取文件輸入流對象,由於<input>中聲明的是name="logo"

function doUpload() {
    $.ajax({
        url: 'http://localhost:3000/upload-single',
        type: 'POST',
        cache: false, //沒必要須
        data: new FormData($('#uploadForm')[0]),
        processData: false,//必須
        contentType: false,//必須
        success: function(data) {
            console.log(data)
        }
    })
}

參考文檔
Github MyDemo
Github Multer
MDN FormData對象的使用

自動化測試 mocha

Mocha('摩卡'),誕生於2011年,如今比較流行的JavaScript測試框架之一,能夠運行於Node環境和瀏覽器環境

測試框架:能夠運行測試的工具。經過他,能夠爲JavaScript應用 添加測試,從而保證代碼質量

參考文檔
mochajs
mocha中文文檔

安裝配置

使用npm 全局安裝

$ npm install --global mocha

項目依賴 局部安裝

$ npm isntall mocha

基本語法

assert 斷言

  • 斷言庫:chai
  • should 風格斷言
  • expect 風格斷言

全局安裝chai

npm install chai -g

案例使用

遞歸執行

$ mocha test --recursive
相關文章
相關標籤/搜索