关于objective-c:Nodejs-学习笔记

5次阅读

共计 13642 个字符,预计需要花费 35 分钟才能阅读完成。

Nodejs 学习笔记

** 这个公众号会继续更新技术计划、关注业内技术动向,关注一下老本不高,错过干货损失不小。
↓↓↓**


一、Nodejs 介绍

(一)根本介绍

Node.js 是一个 JavaScript 运行环境(runtime),它让 JavaScript 能够开发后端程序,简直能实现其它后端语言的所有性能。

Nodejs 最善于的是解决高并发:在 Java、PHP 或者 .net 等服务器端语言中,会为每一个客户端连贯创立一个新的线程。而每个线程须要消耗大概 2MB 内存。也就是说,实践上一个 8GB 内存的服务器能够同时连贯的最大用户数为 4000 个左右。

要让 Web 应用程序反对更多的用户,就须要减少服务器的数量,而 Web 应用程序的硬件老本就回升了。

Node.js 不为每个客户连贯创立一个新的线程,而仅仅应用一个线程。当有用户连贯,就触发一个外部事件,通过非阻塞 I/O、事件驱动机制,让 Node.js 程序宏观上也是并行的。

应用 Node.js,一个 8GB 内存 的服务器,能够同时解决超过 4 万用户的连贯。

(二)开发工具

举荐应用 VSCode

装置好 Node Snippets 插件

二、HTTP 模块、URL 模块、supervisor 工具

(一)HTTP 模块

如果应用 PHP 来编写后端 diamante,须要 Apache 或者 Nginx 的 HTTP 服务器,来解决客户端的申请响应。不过对 Node.js 来说,概念齐全不一样。应用 Node.js 时,咱们不仅仅在实现一个利用,同时还实现了整个 HTTP 服务器。

Tips : ctrl + c 终止服务器

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

/*
    request:获取 url 传过来的信息
    response:给浏览器响应信息
*/
http.createServer(function (request, response) {
  // 设置响应头
  response.writeHead(200, {'Content-Type': 'text/plain'});
  // 示意给咱们的页面下面输入的一句话并且完结响应
  response.end('Hello World');
}).listen(8081); // 端口

console.log('Server running at http://127.0.0.1:8081/');

(二)URL 模块

url 模块也是 nodejs 内置模块。

通过 parse 并设置 true,会将参数转成对象,从对象中取值。

const url = require('url');

var api = 'http://www.itying.com?name=zhangsan&age=20'

// console.log(url.parse(api,true));

var getValue = url.parse(api,true).query;

// console.log(getValue)

console.log(getValue.name)

(三)Nodejs 自启动工具 supervisor

supervisor 会不停的 watch 利用上面的文件,发现有文件被批改,会立即看到变更后的记功,无需重新启动 nodejs

  1. 装置 supervisor

npm install -g supervisor

  1. 应用 supervisor 代替 node 命令启动利用

supervisor app.js

二、CommonJs 和 Nodejs 模块

用 CommonJS API 编写出的利用,不仅能够利用 JavaScrip 开发客户端利用,而且还能够编写以下利用:

  1. 服务器端 JavaScript 应用程序
  2. 命令行工具
  3. 桌面图形界面应用程序

CommonJS 就是模块化的规范,nodejs 就是 CommonJS(模块化)的实现。

(一)模块

  1. 外围模块:Node 提供的模块
  2. 文件模块:用户编写的模块

(二)CommonJS(Nodejs)中自定义模块的规定

(三)应用 demo

tools.js

function formatApi(api) {return "http://www.baidu.com" + api;}

exports.formatApi = formatApi;

如果是裸露一整个对象的所有办法,能够通过:

module.exports.xxx = obj;

如果是想一个一个裸露单个办法,能够通过 exports 进行裸露:

exports.xxx = function() {console.log('hello world')
};

request.js

exports.get = function() {console.log('hello world')
};

exports.post = function() {console.log('hello world')
};

应用场景:

const request = require('./request.js');

request.get();

(四) 如何 require 的时候不写目录

var db = require(‘db’);

// 本人创立的会导入失败,因为 Nodejs 会默认查找 node_modules 对应模块外面的 index.js

能够配置 package 实现能够间接 require 文件

npm init –yes

package.json 是配置文件

三、Nodejs 中的包、npm、第三方模块、package.json 以及 cnpm

(一)包与 NPM

Nodejs 中除了它与本人提供的外围模块外,咱们还能够自定义模块,也能够应用第三方的模块。

  1. 完全符合 CommonJs 标准的包目录个别蕴含如下这些文件:

(1)package.json:包形容文件

(2)bin:用于寄存可执行二进制文件的目录

(3)lib:用于寄存 JavaScript 代码的目录

(4)doc:用于寄存文档的目录

在 NodeJs 中通过 NPM 命令来下载第三方的模块(包)。

  1. npm

npm 是世界上最大的凋谢源代码的生态系统,能够通过 npm 下载各种各样的包和工具。

容许用户将本人编写的包或命令行程序上传到 NPM 服务器供他人应用。

(1)装置模块

 示例:装置 md5 模块的步骤:(1)在 https://www.npmjs.com/ 中找到相应的模块(2)在本人相应的目录里装置模块 npm install md5 --save

增加了 --save,会在 package.json 中展现相应的依赖,而后能够通过 npm i 或者 cnpm i 就会把我的项目所须要的依赖一个一个装置上。(3)引入应用 

(2)卸载模块

npm uninstall xxxx

(3)查看我的项目里的包

npm list

(4)查看包的信息

npm info md5

(4)指定版本装置

npm install xxx@2.1.4

Node-Media-Server:通过 Node-Js 搭建流媒体服务器

(5)npm i

如果删掉 node_modules,能够通过此命令找到 package.json 找到对应的所有包信息

(二)package.json

package.json 定义了我的项目的各种模块,以及各种配置信息和依赖。

“md5″:”^2.2.1”

如果要指定就用某一个版本,把 ^ ~ * 标识符去掉就好了

  • ^ > ~

(三)淘宝镜像

淘宝 NPM 镜像是一个实现的 npmjs.org 镜像,同步频率为 10 分钟 一次,解决 npm install 速度慢的问题。

四、Nodejs 中的 fs 模块

fs 模块是内置模块,只有用于文件操作

1. fs.stat 检测是文件还是目录
2. fs.mkdir 创立目录
3. fs.writeFile 创立并写入文件
4. fs.appendFile 追加文件
5. fs.readFile 读取文件
6. fs.readdir 读取目录下的所有文件名
7. fs.rename 重命名
8. fs.rmdir 删除目录
9. fs.unlink 删除文件 

(一) 理论用例

const fs = require('fs');

// 1. fs.stat 查看是文件还是目录

fs.stat('./html',(err,data) => {if(err) {console.log(err);
        return
    }
    console.log('是文件:' + data.isFile())
    console.log('是文件:' + data.isDirectory())
}) 
// 2.fs.mkdir 创立目录,如果已存在目录,则失败
fs.mkdir('./css',(err)=>{if(err) {console.log(err);
        return;
    }
    console.log('创立胜利');
})
// 3. fs.writeFile 创立写入文件
// 如果文件曾经存在,则会覆盖文件
fs.writeFile('./html/index.html','你好 nodejs',(err)=> {if(err) {console.log(err);
        return;
    }
    console.log('创立写入文件胜利');
})
// 4. fs.appendFile 追加文件
// 如果文件已存在,则会在文件尾部追加内容
fs.appendFile('./css/base.css','你好 nodejs',(err)=> {if(err) {console.log(err);
        return;
    }
    console.log('追加文件胜利');
})
// 5. fs.readFile 读取文件
// 读取到的是十六进制的 buffer 数据,要转换成 string 类型
fs.readFile('./html/index.html',(err,data)=>{if(err) {console.log(err);
        return;
    }
    console.log(data.toString());
})
// 6. fs.readdir 读取目录下的所有文件名
fs.readdir('./html',(err,data)=>{if(err) {console.log(err);
        return;
    }
    console.log(data.toString());
})
// 7. fs.rename 重命名
// 性能 1:重命名
// 性能 2:挪动文件
fs.rename('./css/base.css','./css/index.css',(err)=>{if(err) {console.log(err);
        return;
    }
    console.log('重命名胜利');
})
// 8. fs.rmdir/unlink 删除目录
// 当目录里有文件时,不能间接删除目录,要通过 fs.unlink 先把文件删除,再应用 rmdir 删除目录
fs.unlink('./html/index.html',(err) =>{if(err) {console.log(err);
        return;
    }
    console.log('删除文件胜利');
})

(二)fs 模块的应用

实例 1:

判断服务器下面有没有 upload 目录,如果没有创立这个目录,如果有的话不做操作(图片上传)

const fs = require('fs');

// 实例 1:判断服务器下面有没有 upload 目录,如果没有创立这个目录,如果有的话不做操作(图片上传)var path = './upload';
fs.stat(path,(err,data) => {if(err) {
        // 执行创立目录
        mkdir(path);
    }
    if(!data.isDirectory()){
        // 首先删除文件,再去执行创立目录
        fs.unlink(path,(err)=>{if(!err) {mkdir(path);
            }else{console.log('请检测传入的数据是否正确');
            }
        })
    }
})

function mkdir(dir) {fs.mkdir(dir,(err)=> {if(err) {console.log(err);
            return
        }
    });
}

实例 2:

介绍 mkdirp 这个模块,这个创立层级目录 ./xxx/aaa/bbb

  1. https://www.npmjs.com/package…
  2. npm i mkdirp –save
  3. var mkdirp = require(‘mkdirp’);
  4. 看文档应用

实例 3:

wwwroot 文件夹上面有 images css js 以及 index.html, 找出 wwwroot 目录上面的所有目录,并放到一个数组中

fs 所有的办法其实是一个异步办法,循环是做不到的。

解决形式:

  1. 革新 for 循环,用递归实现

  1. nodejs 外面的新个性 async await

五、async await 的应用,以及应用 async await 解决异步

(一)ES6 常见语法的应用

  1. let const

let 是一个块作用域

let 和 var 是一样的用来定义变量的

if(true) {var a = 123;}
console.log(a);   // 是会打印出 123 的 
if(true) {let a = 123;}
console.log(a);  // 会报错没有定义 a 变量 

const 就是不可扭转

  1. 箭头函数
  2. 对象、属性的简写

  1. 模板字符串
var name = '张三';
var age = 20;
console.log(`${name} 的年龄是 ${age}`)

用的不是单引号包裹的,用的是 Tab 上的富豪 ·

  1. Promise 解决异步问题

在 ES6 进去之前,应用内部获取异步办法来获取数据:

function  getData(callback) {
    //ajax
    setTimeout(function() {
        var name = '张三';
        callback(name);
    },1000);
}

// 内部获取异步办法外面的数据

getData(function(test){console.log(test)
})

Promise 来解决异步

var p = new Promise(function(resolve,reject) {
    // resolve:胜利的回调
    // reject:失败的回调
    setTimeout(function() {
        var name = '张三';
        resolve(name);
    },1000);
})

p.then(function(data) {console.log(data);
})

(二)async、await 和 promise 的应用

async:让办法变成异步

await:期待异步办法执行实现

async function test() {return '你好 nodejs';}

console.log(test());  // ==> 输入:Promise {'你好 nodejs'}

await:必须用在 async 办法里

async function test() {return '你好 nodejs';}

async function main() {var data = await test(); // 获取异步办法里的数据
    console.log(data);
}

main();

(三)异步办法检测目录习题

const fs = require('fs');

var dirArr = [];
var path = './wwwroot';

// 1. 定义一个 isDir 办法判断一个资源到底是目录还是文件
async function isDir(path) {return new Promise((resolve,reject) => {fs.stat(path,(error,stats)=> {if(error) {console.log(error);
                reject(error);
                return
            }
            if(stats.isDirectory()){resolve(true);
            }else{resolve(false);
            }
        })
    })
}

// 2. 获取 wwwroot 外面的所有资源,循环遍历

function main() {fs.readdir(path,async(err,data)=> {if(err) {console.log(err);
            return;
        }

        for(var i = 0 ; i < data.length ; i ++) {if(await isDir(path + '/' + data[i])) {dirArr.push(data[i]);
            }
        }

        console.log(dirArr);
    })
}

main();

六、Nodejs fs 中的流以及管道流、复制文件、复制图片

  1. fs.createReadStream 从文件流中读取数据
const fs = require('fs')

var readStream = fs.createReadStream('./data/input.text');

readStream.on('data',(data) => {// 监听读取进度,会屡次回调})

readStream.on('end',(data) => {// 读取结束})

readStream.on('error',(data) => {// 读取失败})
  1. fs.createWriteStream 向文件中写入流数据
const fs = require('fs')

var str = '';

for(var i = 0 ; i < 100; i ++) {str += 'test';}

var writeStream = fs.createWriteStream('./data/output.text');

writeStream.write(str);

writeStream.on('finish',()=>{console.log('write suc')
})
  1. 管道流:将数据从一个文件复制到另外一个文件,利用场景:大文件、图片

七、利用 HTTP 模块、Url 模块、Path 模块、fs 模块创立一个动态 WEB 服务器

预期实现的指标:

  1. 能够让咱们拜访 web 服务器下面的网站
var http = require('http');
var fs = require('fs');
const common = require('./common');
const {runInNewContext} = require('vm');
const path = require('path');

http.createServer(function (req, res) {

    // 1. 获取地址
    let pathName = req.url;
    pathName = (pathName == '/') ? '/index.html' : pathName; // 重定向
    let extname = path.extname(pathName); // 能够获取后缀名
    console.log(pathName);

    // 2. 通过 fs 模块读取文件
    if (pathName != '/favicon.ico') {console.log('begin read File');
        fs.readFile('./' + pathName,(err,data) => {if (err) {console.log('read File fail');
                res.writeHead(404, {'Content-Type': 'text/html;charset="utf-8"'});
                res.end('页面不存在');
            } else {console.log('read File suc');
                let mime = common.getMime(extname);
                res.writeHead(200, {'Content-Type': ''+mime+';charset="utf-8"'});
                res.end(data);
            }
        })
    }
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

八、Express 介绍

Express 是一个基于 Node.js 平台,疾速、凋谢、极简的 web 开发框架,它提供一系列弱小的个性,帮忙你创立各种 Web 和 挪动设施利用。

(一)根本申请类型

const express = require('express');
const app = express(); // 实例化 express

// 配置路由:get\post\put\delete
app.get('/',(req,res)=>{res.send('你好 express');
})

app.get('/admin/user',(req,res)=>{res.send('配置二级目录');
})

// post 是无奈在浏览器里间接申请的,能够应用 Postman 软件模仿申请
app.post('/doLogin',(req,res)=>{res.send('执行登录');
})

// put 示意批改数据,也是一种申请类型
app.put('/editUser',(req,res)=>{res.send('批改用户');
})

// delete 删除数据
app.delete('/deleteUser',(req,res)=>{res.send('删除数据');
})

app.listen(3000); // 监听 3000 端口 

(二) 动静路由与动静路由配置程序

const express = require('express');
const app = express(); // 实例化 express

// 动静路由,配置动静路由是有程序的,如果想独自配置 /article/add,要在 '/article/:id' 动静路由前配置好,不然会被动静路由捕捉
app.get('/article/:id',(req,res)=>{var id = req.params['id'];
    res.send('动静路由'+id);
})

app.listen(3000); // 监听 3000 端口 

(三)获取 get 申请中的参数

const express = require('express');
const app = express(); // 实例化 express

// get 传值 
app.get('/product',(req,res)=>{
    let query = req.query;
    console.log(query);
    res.send('product-' + query.id);
})

app.listen(3000); // 监听 3000 端口 

九、Express Ejs 动态文件托管

(一)绑定数据

<%=xxx%> 绑定对象和属性

(二)解析 html

<%-xxx%> 能够解析 xxx 对应的 html 代码,

比方 xxx 能够为:

const express = require('express');
const app = express(); // 实例化 express
 // 配置 ejs 模板引擎(因为 express 默认集成 ejs)app.set('view engine','ejs');

app.get('/news',(req,res)=> {
    var userInfo = {
        username:'张三',
        age:20
    }

    let article = "<h3> 我是一个 h3</h3>"
    
    res.render('news',{
        userInfo:userInfo,
        article:article
    });
})

app.listen(3000); // 监听 3000 端口,倡议写成 3000 以上,3000 以下的端口会被计算机软件占用 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2> 我是一个 ejs 模板引擎 </h2>
    <p><%=userInfo.username%></p> 
    <p><%-article%></p> 
</body>
</html>

(三)条件判断

    <%if(score>=60){%>
        <p> 及格 </p>
    <%}else{%>
        <p> 不及格 </p>
    <%}%>

(四)循环遍历

(五)在 ejs 模板里引入其余模板

(六)指定模板地位,默认模板地位在 views

app.set(‘views’,__dirname + ‘/views’);

(七)Ejs 后缀批改为 html

(八)中间件

艰深地讲:中间件就是匹配路由之前或者匹配路由实现做的一系列的操作,中间件中如果想往下匹配的话,那么须要些 next()

Express 利用可应用如下几种中间件:

  1. 利用级中间件(用于权限判断)

实现在匹配 get/post 之前,打印下以后日志:

// 利用级中间件
app.use((req,res,next)=>{console.log(new Date());
    next();// 如果不写这个 next, 匹配到这里就完结了})
  1. 路由级中间件(用得比拟少)

通过增加 next,能够让路由匹配到 /article/add 之后,还能够持续匹配 /article/:id。

app.get('/article/add',(req,res,next)=>{console.log('路由级中间件');
    next();})

app.get('/article/:id',(req,res)=>{var id = req.params['id'];
    res.send('动静路由'+id);
})
  1. 错误处理中间件

针对匹配不到的路由,返回状态码 404,相当于兜底逻辑

app.use((req,res,next)=>{res.status(404).send("404");
})
  1. 内置中间件 (匹配路由之前,先在内置中间件查找相应的文件)

app.use(express.static(‘static’))

  1. 第三方中间件

(1)body-parser 获取 post 传过来的数据

十、在 Express 中应用 Cookie

Cookie 是存储于访问者的计算机中的变量,能够让咱们用同一个浏览器拜访同一个域名的时候共享数据。

HTTP 是无状态协定,简略地说:当你浏览了一个页面,而后转到同一个网站的另一个页面,服务器无奈意识到这是同一个浏览器在拜访同一个网站。每一次拜访都是没有任何关系的。

Cookie 是一个简略到爆的想法:当拜访一个页面的时候,服务器在上行 HTTP 报文中,命令浏览器存储一个字符串;浏览器再拜访同一个域的时候,将把这个字符串写到到上行 HTTP 申请中。

第一次拜访一个服务器,不可能携带 Cookie,必须是服务器失去这次的申请,在上行响应报文中,携带 Cookie 信息,尔后每一次浏览器往这个服务器收回的申请,都会携带这个 cookie。

(一)cookie-parser 的应用

const express = require('express');
const app = express(); // 实例化 express
const cookieParser = require('cookie-parser');

// 配置路由:get\post\put\delete
app.get('/',(req,res)=>{
    // 设置 cookie
    res.cookie('key_mock','value_mock',{maxAge:1000*60*60});// 设置 cookie 过期工夫 maxAge
    res.send('你好 express');
})

app.get('/admin/user',(req,res)=>{
    // 获取 cookie
    var key_mock = req.cookies.key_mock;
    console.log(key_mock);
    res.send('配置二级目录');
})

前期应用 cookie 须要对 cookie 进行加密

Cookie 配置的参数:

  • maxAge:过期工夫
  • expires:设置具体过期期间(用得比拟少)
  • path:设置 cookie 拜访的目录(也即哪些路由能够拜访 cookie)
  • httpOnly:true,只能在后端设置 cookie,false 示意前端也能够设置 cookie
  • secure:true 示意在 HTTP 有效,只有 HTTPS 才是无效的
  • signed:示意是否签名 cookie,设为 true 会对这个 cookie 签名,这样就须要用 res.signedCookies 而不是 res.cookies 拜访它。被篡改的签名 cookie 会被服务器回绝,并且 cookie 值会重置为它的原始值。

多个域名共享 cookie:同个域的二级域名共享 cookie

  • aaa.itying.com
  • bbb.itying.com
res.cookie('key_mock','value_mock',{maxAge:1000*60*60,domain:'.itying.com'});

(二)cookie 的加密

cookie 的加密

  1. 配置中间件的时候须要传入加密的秘钥

app.use(cookieParser(‘itying’))

  1. 设置 cookie
    res.cookie(‘key_mock’,’value_mock’,{maxAge:10006060,signed:true});
  2. 获取 cookie
    let username = res.signedCookies.username

十一、Session 的根本应用

Session 是另一种记录客户状态的机制,不同的是 Cookie 保留在客户端浏览器中,而 session 保留在服务器上。

(一)Session 的工作流程

浏览器拜访服务器并发送第一次申请

服务器端会创立一个 session 对象,生成一个相似于 key、value 的键值对

而后将 key(cookie)返回到浏览器(客户)端

浏览器下次再拜访时,携带 key(cookie)申请服务器,找到对应的 session(value)

Tips:一个 get 申请只能写一个 req.send,写两个 send 会导致失败

const express = require('express')
const session = require('express-session')
const app = express()
const port = 3001
// 配置 session 的中间件
app.use(session({
    secret: 'keyboard cat', // 服务器端生成 session 的签名
    name: 'itying', // 批改 session 对应的 cookie 名称(即 key)resave: false, // 强制保留 session 即便它并没有变动
    saveUninitialized: true, // 强制将未初始化的 session 存储
    cookie: {
        maxAge: 1000 * 60,
        secure: false // true 示意只有 https 协定能力拜访 cookie
    },
    rolling: true // 在每次申请时强行设置 cookie,这将重置 cookie 过期工夫(默认:false)}))

app.get('/', (req, res) => {
    // 获取 session
    if (req.session.username) {res.send(req.session.username + '- 已登录')
        return;
    }
    res.send('没有登录!')
})

app.get('/login', (req, res) => {
    // 设置 session
    req.session.username = '张三'
    res.send('已登录')
})

app.listen(port, () => console.log(`Example app listening on port port!`))

Tips2: VSCode 代码格式化 快捷键 On Mac Shift + Option + F

(二) 销毁 session

app.get('/loginOut',(req,res)=>{
    // 1. 设置 Session 的过期工夫为 0(它会把所有的 session 都销毁)req.session.cookie.maxAge = 0;

    // 2. 销毁指定 session
    req.session.username = '';

    // 3. 应用 destroy 销毁 session
    req.session.destroy()

    res.send('退出登录!')
})

十二、分布式架构配置 Session

在北京服务器设置了 session,而后负载平衡,Nginx 服务器可能会在上海的服务器里取获取 session。

所以这时须要把 session 放到数据库中,比方应用 mango DB。

(一)connect-mongo

后盾通过数据库解决数据不统一的问题,可选的数据库:

  • mongoDB
  • mysql
  • redis
/*
session 保留在数据库外面

1. 配置 express-session

2. 装置 connect-mongo

3. 引入 mongo
const MongoStore = require('connect-mongo')(session);

4. 配置中间件
app.use(session({
    secret: 'keyboard cat', // 服务器端生成 session 的签名
    name: 'itying', // 批改 session 对应的 cookie 名称(即 key)resave: false, // 强制保留 session 即便它并没有变动
    saveUninitialized: true, // 强制将未初始化的 session 存储
    cookie: {
        maxAge: 1000 * 60,
        secure: false // true 示意只有 https 协定能力拜访 cookie
    },
    rolling: true, // 在每次申请时强行设置 cookie,这将重置 cookie 过期工夫(默认:false)store: new MongoStore({
        url: 'mongodb://127.0.0.1:27017/shop',
        touchAfter:24 * 3600 // 不论收回了多少申请,在 24 小时之更新一次 session,除非你扭转了 session
    })
}))
*/

十三、Express 路由模块化

Express 中容许咱们通过 express.Router 创立模块化的、可挂载的路由处理程序。

把性能类似的路由进行模块化解决(有点相似 JavaScript 应用 exports 裸露办法和属性,只是 express 把提供的 get 办法 进行了 exports 的解决)

挂载 login 模块:

本文由博客一文多发平台 OpenWrite 公布!

正文完
 0