node.js笔记

Node

概述

Node是一个基于Chrome V8引擎的JavaScript代码运行环境

安装

下载

官方网址:https://nodejs.org/en/

LTS:Long Term Support 长期支持版(稳定版)。

Current:拥有最新特性版本(实验版)。

验证

在windows PowerShell(超级管理员命令行)输入node -v,如果有版本返回那么就安装完毕。没有则失败。

组成

node.js是由ECMAScript及Node环境提供的一些附加API组成的。

执行

在命令行执行,使用node 文件名称(包含尾缀)命令执行js文件。

按住Shift + 鼠标右键 可快速打开管理员命令行。

Ctrl + c键终止程序。

windows PowerShell小技巧:

  1. 键盘↑键可以快速输入上次输入的命名。
  2. Tab键快速补充。
  3. clear 清屏。

同步API和异步API

概述

同步API:只有当前API执行完毕后,才能继续执行下一个API。

异步API:当前API的执行不会阻塞其他API执行。

区别
  1. 同步API可以通过返回值拿到API执行结果,但是异步API不行。–返回值

  2. 同步API是从上向下的执行,前面代码会堵塞后面的代码的执行。–执行顺序

    异步API不会等待API执行完成后再向下执行代码。

Node.js全局对象global

在游览器中全局对对象是window,在Node中全局对象是global

Node中全局对象可以使用以下方法,可以在任意位置使用,global可以省略。

  • console.log() 在控制台打印输出
  • setTimeout() 设置定时器
  • clearTimeout() 清除定时器
  • setInterval() 设置间歇定时器
  • clearInterval() 清除间歇定时器

异步任务解决方案

Promise

概述

Promise的目的是解决Node.js异步编程中回调地狱的问题,分离结果和错误。降低代码的维护难度。

回调地狱:在异步任务嵌套异步任务,嵌套层数过多。

使用
let 变量名(promise) = new Promise(function(resolve,reject) {
    resolve:是一个函数,当异步任务有结果时,当做参数传递出去(当做了promise中方法回调函数的参数,再传递给我们使用)。
    reject:是一个函数,当异步任务执行失败,可以通过参数传递出去。
});
在外面使用异步任务结果:
异步任务执行成功时:
promise.then(function(result) {
    
});
异步任务执行失败时:
promise.catch(function(result) {
    
});
使用链式编程时:
promise.then(function(result) {//成功时
    //可以使用return返回值,返回的值就是下个.then()方法的被执行对象。(这样就可以实现链式编程)
}).catch(function(err) {//失败时
    
});
示例
const fs = require('fs');//引入fs模块

let pormise = new Promise(function (resolve,reject){//创建Promise对象
    
	fs.readFile('路径地址path','字符集utf8',function(err,result) {//创建读取文件的异步任务
        
		if (err != null) {//判断读取是否成功:失败,就是用reject函数以参数的形式传递出去
            reject(err);
            }else {//如果成功,那么就使用resolve函数以参数的形式传递出去
            resolve(result);
        }
        
	});
    
});

pormise.then(function(result) {//成功时,处理函数
    
}).catch(function(err) {//失败时,处理函数
    
});

异步函数

概述

异步函数时异步编程的终极奥义解决方案,它的作用是将我们的异步代码书写成同步的形式,使其代码更易阅读,降低代码维护难度。

语法
//1.在普通函数之前添加 async 关键字将其转换为异步函数。
//2.异步函数默认的返回值就是Promis对象。
修饰符 变量名 = async function() {
    
};
async function 函数名称() {
    return 返回值;//这个返回值可以使用.then方法进行使用、
    throw 抛出错误信息;//使用throw关键字,可以抛出错误信息。使用catch方法使用该抛出打错误信息。
}

注意:
1.如果有函数有返回值,它的返回值是基于Promis对象。返回值为Promis的属性或者方法。
使用
async function fn() {
    return 'fn';//这个返回值可以使用.then方法进行使用、
    throw '这是fn的错误信息';//使用throw关键字,可以抛出错误信息。使用catch方法使用该抛出打错误信息。
}
async function fn2() {
    return 'fn2';//这个返回值可以使用.then方法进行使用、
    throw '这是fn2的错误信息';//使用throw关键字,可以抛出错误信息。使用catch方法使用该抛出打错误信息。
}
async function fn3() {
    return 'fn3';//这个返回值可以使用.then方法进行使用、
    throw '这是fn3的错误信息';//使用throw关键字,可以抛出错误信息。使用catch方法使用该抛出打错误信息。
}

async function run() {//使用async关键字,将普通函数声明称异步函数
    await fn()//使用await关键字,可以堵塞代码,就是fn()函数没有执行结果返回就不往下执行了。这样就可以达到一一读取的效果。
	await fn2();
	await fn3();
}

注意
  • async:使用此关键字可以将普通函数转化为异步函数。
  • 异步函数的返回值默认为Promis对象。
  • 在异步函数内部可以使用return关键字进行结果返回,结果会被包含在Promis对象中。
  • 在异步函数内容可以使用throw关键字抛出错误信息。
  • 在异步函数外面可以通过Promis对象中then方法使用异步函数的返回值。
  • 在异步函数外面可以通过Promis对象中的catch方法获取异步函数的错误信息。
  • await:【只能在异步函数中使用,后面必须跟Promis对象】使用该关键字可以堵塞异步函数的执行,只有当前函数有返回值结果才可以往下执行。

在Node.js中解决fs.readFild异步函数的方法

在Node.js中提供了可以将fs.readFild方法返回值转换为Promis对象的方法。这个方法就是-util内置模块下的promisify对象。

const fs = require('fs');//引用fs模块
const promisify = require('util').promisify;//获取promisify对象
const readFile = promisify(fs.readFile);//使用promisify对象将fs.readFile方法的返回值转换为Promis对象
async function() {
    let 变量名 = await readFild('路径地址path','字符集utf8');
}

Node.js模块化开发

JavaScript开发弊端

JavaScript开发弊端时,存在两大问题:文件依赖命名冲突

Node.js中模块化开发规范

node.js规定一个JavaScript文件就是一个模块,模块内部定义的变量和函数默认情况下在外部无法访问

模块内部可以使用exports对象进行成员导出,使用requier方法导入其他模块。

导出
exports.属性名 = 被导出对象;
导入
修饰符 变量名 = require(路径地址);//导入路径地址可以省略后缀(.js)。

属性导出的另一种方法:
module.exports.属性名 = 被导出对象;
注意:exports是module.exports的别名(地址引用关系),导出对象最终以module.exports为准。

系统模块

系统模块:就是Node运行环境提供的API,因为这些API是模块化开发的,所以我们也称为Node运行环境提供API为系统环境。

系统模块fs文件操作

f:File文件,s:System系统,文件操作系统。

使用前需要引用fs模块。

读取文件内容
fs.readFile('文件路径地址',[文件编码],回调函数callback);
fs.readFile('文件路径地址',[文件编码],function(错误err【读取信息,无错误为null,对象doc【文件读取结果】) {
    
});
写入文件内容
fs.writeFile('文件路径地址','写入内容',回调函数callback);
fs.writeFile('文件路径地址','写入内容',function(错误err【读取信息,无错误为null) {
    //如果文件不存在,那么writeFild方法会帮你创建一个新文件。
});
系统模块path路径操作
路径拼接语法
path.join('路径','路径',...);//将传参路径地址拼接,返回值为拼接结果(字符串)。
相对路径or绝对路径

相对路径:相对于**执行工具(命令行)**出发的路径。

绝对路径:以盘符为原点出发的路径。

使用**_ _dirname**获取当前目录的绝对路径。

在html文件中会外联许多文件,比如:
css/base.css
改成绝对路径:
/css/base.css
绝对路径是直接输入在浏览器的,不会和之前的文件拼接。而相对路径,如果访问的网页已经在文件夹中,那么它会拼接之前的文件夹。
URL模块

功能:URL模块可以解析请求对象的url地址。

const http = require('http');//引用http模块
const url = require('url');//引用url模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
	let url = url.parse(请求对象.url,布尔值(是否将返回值以对象形式返回));
    url对象属性:
    pathname:请求地址
    query:?之后的参数信息
});
app.listen(端口号);//监控端口

第三方模块

第三方模块是别人写好的、具有特定功能的,我们可以直接使用的模块。第三方模块也是包。

第三方模块存在的两种形式:

  1. 以js文件的形式存在,提供实现项目具体功能的API接口。
  2. 以命令行工具形式存在,辅助开发工具。

npm(node package manager):是node的第三方模块管理工具。

在windows PowerShell下输入
npm install 模块名称;//下载第三方模块(默认下载到命令行当前目录)。可以同时下载多模块,用空格相隔。
npm uninstall package 模块名称;//删除第三方模块。

nodemon

nodemon是一个命令行工具,可以辅助项目开发。

在Node.js中,每次修改文件都要在命令行中重新执行该文件,非常繁琐。

使用步骤
1.使用npm install nodemon -g//下载nodemon,-g全局安装。
2.ctrl + c//停止监听

nrm

nrm(npm registry manager):npm下载路径切换工具。

使用环境:国内访问官方网站速度较慢,可以使用一些国内搭建的网站代替。

使用步骤
1.使用npm install nrm -g//下载nrm,-g全局安装。
2.查询可使用下载地址列表nrm ls
3.切换npm下载地址nrm use 下载地址名称

Gulp

基于node平台开发的前端构建工具。

将机械化操作编写成任务,想要执行机械化操作时只需执行一个命令即可。提高了开发效率。

功能:

  1. 项目上线前,HTML、CSS、JS文件压缩合并。
  2. 语法转换(es6、less…)。
  3. 公共文件抽取。
  4. 修改文件游览器自动刷新。
使用步骤
1.使用npm install gulp//下载gulp库文件
2.在项目根目录下,创建gulpfile.js文件。
3.重构项目的文件夹结构,src目录放置源代码文件 dist目录放置构建后的文件。
4.在gulpfile.js文件中编写任。
	(1)引入gulp模块
    (2)使用gulp模块,编写任务。
5.在命令行工具中执行gulp任务。
	(1)在命令行通过npm install gulp-cli -g//安装gulp命令行工具(-g全局安装)2)安装后。执行gulp 任务名称//执行任务
     
执行过程出现的常见错误:
[23:46:01] The following tasks did not complete: test
[23:46:01] Did you forget to signal async completion?
解决方案:
给使用task创建任务的参数列表中回调函数,添加参数,并且回调一下即可。
gulp.task('任务名称',function(参数名) {
    参数名();//最后调用
});
方法
1.gulp.scr():获取文件
gulp.scr('路径地址');

2.gulp.dest():输出文件
注意:gulp.dest()方法必须写在任务.pipe()的括号中。

3.gulp.task():建立gulp任务
gulp.task('任务名称',回调函数);
gulp.task('任务名称',function() {
    
});
gulp.task('default',['任务列表']);//当执行这个任务时,任务列表中的任务也会被执行。这个任务称为“构建任务”。【旧】
新版本:使用paralle或者使用series把任务包括起来。
4.gulp.watch():监控文件变化
插件
gulp-htmlmin:html文件压缩
gulp-csso:压缩css文件
gulp-babel:javascript语法转换
gulp-less:less语法转换
gulp-uglify:压缩混洗javascript
gulp-file-include:公共文件包含
browsersync:浏览器实时同步

使用插件步骤:
1.使用npm工具下。
2.创建任务时引用模块。
注意:主要根据API进行操作。

gulp-file-include公共文件包含的简单使用步骤:
1.使用npm工具下:npm install --save-dev gulp-file-include。
2.创建任务时引用模块:const fileinclude = require('gulp-file-include');3.需要引入公共部分的html文件中书写:@@include('公共代码路径地址')

Package.json文件的说明

项目描述文件,记录了当前项目信息。例如:项目名称、版本、作者、gulpub地址。当前项目依赖第三方模块。

  1. 使用npm init -y命令生成(-y是使用默认配值)。
package.json文件内容:
{
  "name": "description",//项目名称
  "version": "1.0.0",//版本号
  "description": "",//项目描述
  "main": "index.js",//项目主入口文件
  "scripts": {//命令别名
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],//关键字
  "author": "",//项目作者
  "license": "ISC"//项目协议
  "dependencies":{//项目依赖模块
      
  }
  "devDependencies":{//开发依赖模块
      
  }
}
使用npm install,不加任何模块名,它会去找package.js文件,自动下载所有依赖模块。
npm install--production//下载 项目依赖 模块

scripts别名的使用:
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
    //"别名":"命令"
  },
在命令行输入npm run 别名,就可以执行别名中的命令了。
使用环境:命令较长时,起别名更加高效。
项目依赖

在项目的开发阶段和上线运营阶段,都需要依赖的第三方包,称为项目依赖。

可以通过npm install命令下载的文件会默认被添加到package.json项目说明文件中。

开发依赖

在项目开发中使用的模块,但是上线运营不需要。

使用npm install 包名 --save-dev 命令将不会添加到package.json文件中。

package-lock.json文件作用
  1. 锁定包的版本,确定再次下载不会因为版本不同而产生问题。
  2. 加速下载速度,因为该文件已经记录了项目模块依赖关系和下载地址,所有再次下载不用再次解析模块依赖关系和下载地址。

mime模块

mime模块可以帮助我们判断读取文件的类型

使用步骤
1.下载模块:npm install mime
2.在js文件中引入模块:const mime = require('mime');
3.使用模块中的getType('路径地址path')方法判断读取文件的类型,返回值就是类型。

router模块

主要功能实现路由,简化代码。

使用步骤
  1. 获取路由对象
  2. 调用路由对象提供的API方法创建路由
  3. 启动路由,使其生效。
代码展示
1.获取路由对象
const getRouter = require('router');//引用模块。
const router = getRouter();//调用getRouter方法获取router路由对象。
2.获取路由对象提供的方法创建路由
router.get('路径path',(request,response) => {//创建get路由处理函数。
    response.end('');
});
3.启动路由,使其生效
server.on('request',(request,response) => {//服务器每次接受请求,就会调用一次路由。
    router(request,response,() => {});//第三个参数回调函数,必填参数。
});

模板引擎

模板引擎第第三方模块,

让开发者一更加友好的方式拼接字符串,是项目更加清晰、更易维护。

art-template模板引擎
1.在命令行工具中使用:npm install art-template
2.在代码中引入该模块:const template = require('art-tmplate');
3.在代码中将模板与特定数据进行拼接:const 变量名 = template('模板路径地址path', 拼接对象);1)返回值为拼接完成的字符串
模板语法

art-template同时支持两种模板语法:标准语法原始语法

标准语法可以让模板更容易读取,原始语法具有强大的逻辑处理能力。

输出

将某项数据输出在模板中。

标准语法:{{数据}}

原始语法:<%=数据 %>

注意:语法中还可以进行简单的运算。比如:加减乘除、三目运算符。

原文输出

如果数据中携带HTML标签,默认模板引擎不会解析标签,会将标签转义后输出。

标准语法:{{@数据}}

原始语法:<%-数据%>

条件判断

在模板中可以根据条件判断显示那块html代码。

标准语法:
单条件:{{if条件}}...{{/if}}
多条件:{{if条件}}...{{else if 条件2}}...{{/if}}
示例:
<div>
	<span>{{if age>18}}年龄大于18时显示{{else if age<18}}年龄小于14时显示{{/if}}</span>
</div>
原生语法:
单条件:<% if (value判断条件) {%>...<%}%>
多条件:<% if () {%> <%} else if () {%> <%}%>
循环

标准语法:{{ecah 数据}}{{each}}

原始语法:<% for() {%> <%}%>

标准语法:
{{each 对象【数组】}}
    {{$index}}//索引
    {{$value}}//值
{{/each}}
原始语法:
<% for (let i = 0; i < 数组.length; i++);{%>
    	<%=i%>
    	<%数组[i]%>
	<%}
=%>
子模板

使用头部模板将网站公共区域(头部、底部)抽离到单独的文件。

标准语法:{{include 模板路径}}

原始语法:<%include(‘模板路径’)%>

模板继承

使用模板继承可是将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架文件。

预留位置
{{block '名称'}} {{/block}}

继承模板
{{extend '骨架文件位置'}}
填充预留位置
{{block '名称'}}填充内容{{/block}}
模板配置
  1. 向模板中导入变量 template.defaults.imports.变量名 = 变量;
  2. 设置模板根目录 template.defaults.root = ‘根目录路径’;设置完根目录之后template(‘文件名称’, 拼接对象),不用书写路径,因为设置默认模板根目录之后,模板引擎会自动去找根目录下找文件。
  3. 设置模板文件默认后缀名 template.defaults.extname = ’后缀名‘;设置之后template(‘文件名称’, 拼接对象),就不用写文件名称的后缀了。

serve-static模块

功能:实现静态资源访问服务。

使用步骤
  1. 引入server-static模块获取创建静态资源服务功能的方法。
  2. 调用方法创建静态资源的方法并指定静态资源服务目录
  3. 启用静态资源服务功能
代码展示
const http = require('http'); //引入http模块
const path = require('path'); //引入path模板
const servestatic = require('serve-static'); //引入serverstatic模块
const static = servestatic(path.join(__dirname, 'public')); //通过serverstatic方法(并指定静态资源目录),获取返回值static对象
app.on('request', (request, response) => {
    static(request, response, () => {}); //调用static方法,启动资源访问服务功能

});
app.listen(80);//监控端口

dateformat模块

主要功能:将Date对象时间格式转换成指定时间格式。

模块执行机制

模块查找规则-没有后缀时
  1. require方法更具模块路径查找模块,如果是完整的路径,直接引入。

  2. 如果路径模块名后面没有后缀,先查找同名js文件在查找同名js文件夹。

  3. 如果找到同名文件夹,就会去找index.js

  4. 如果文件夹中没有index.js就会去当前文佳夹中的package.js文件中查找mian属性(文件主入口)

  5. 没有指定路口文件或者指定路径不对,那么就报错。

模块查找规则-当模块没有路径和后缀时
  1. nods.js会假设它是系统文佳

  2. node.js会去node_modules文佳夹中

  3. 首先查找有没有同名js文件

  4. 如果没有js文件,那么就去找同名文件夹

  5. 如果文件夹中没有index.js就会去文佳夹中的package.js文件中查找mian属性(文件主入口),找到执行

  6. 没有指定路口文件或者指定路径不对,那么就报错。

Express框架

Express框架是基于Node平台的Web应用开发架构,它提供了一系列强大特性,帮助你创建各种Web应用。

Express框架特性

  1. 提供了方便简洁的路由定义方式。(route模块就是从Express框架提取出去的)

  2. 对获取HTTP请求参数进行了简化处理

  3. 对模板引擎支持程度高,方便渲染动态HTML页面

  4. 提供了中间件机制有效控制HTTP请求

  5. 拥有大量第三方中间件对功能进行扩展

基本使用

const express = require('express'); //引入express框架模块
const app = express(); //创建服务器,并返回服务器对象
app.get('/', (request, respone) => { //创建路由
    respone.send('Hello,Express'); //响应客户端
});
app.listen(80); //监控端口

使用send方法好处:
1.send方法会自动检测响应内容的类型
2.send方法会自动设置http状态码
3.send方法会帮我们自动设置响应的内型类型及编码

respone的方法:
res.status(状态码);
改变响应客户端头部信心中的状态码

中间件

中间件就是一堆方法,可以接收客户端的请求,可以对请求做出相应,也可以将请求继续交给下一个中间件继续处理。

中间件的组成

中间件的组成由两部分构成,中间件方法以及请求处理函数。

中间件方法由Express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求。

Express框架下:
服务器对象.get('请求路径',(request, respone) => {});//接收get请求
服务器对象.post('请求路径',(request, respone) => {});//接收post请求
服务器对象.use('请求路径',(request, respone,[next]) => {});//不区分get或者post请求(不区分请求类型)
注意:
use方法如果没有书写请求路径形参,不管什么路径都会执行这个use方法中的处理函数。
注意事项
  1. 可以针对一个请求设置多个中间件(请求地址相同),对同一个请求进行多次处理。
  2. 默认情况下,请求从上自下依次匹配中间件,一旦匹配成功,终止匹配。
  3. 可以条用next()方法将请求的控制权交个下一个中间件,知道遇到结束请求的中间件。
服务器对象.get('请求路径',(request, respone,next) => {});//接收get请求,执行代码后,跳转至下一个中间件。
服务器对象.post(('请求路径',(request, respone,next) => {}) => {});//接收post请求,执行代码后,跳转至下一个中间件。

错误处理中间件

在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取不存在、数据库链接失败。

错误处理中间件是一个集中处理错误的地方。

服务器对象.use('请求路径',(错误信息对象error,request, respone,next) => {});//接收get请求,执行代码后,跳转至下一个中间件。

注意事项:

错误处理中间件无法捕获异步错误信息,需要在书写异步代码时,将错误信息通过next()方法传递给错误处理中间件。

Error

Express框架内置的错误对象

throw new Error('错误信息');

捕获错误

在node.js中,异步API的错误信息都可以通过回调函数获取的,支持Promise对象的异步API发生错误可以通过catch方法捕获。

使用
//包装想要使用try{}catch(error){}捕获异常的方法
const express = require('express'); //引入express框架模块
const fs = require('fs'); //引入fs文件读写模块
const promisify = require('util').promisify; //导入util模块中的promisify方法
const readFild = promisify(fs.readFild);//使用promisify方法promisify方法包装
//异步方法,需要将其转为同步形式(async await)
app.get('/index', async(request, respone, next) => { //添加路由
    try {//try包裹着未异常时执行代码
        let data = await readFile('./01.js');
        respone.send(data + '');
    } catch (error) {//catch包裹着执行出现异常时该执行的代码,尝试继续执行程序,不让程序因错误停止
        next(error);
    }
});

模块化路由

构建模块化路由,有利于后续维护代码。

//引入模块
const express = require('express');
//创建服务器,并获取服务器对象
const app = express();
//获取router对象
const host = express.Router();
//创建一级路由,凡是/host地址的都调用host对象中的路由
app.use('/host', host);
//创建二级路由,/host/index路由处理
host.get('/index', (request, response) => {
    response.status(200).send('欢迎来到首页!');//响应内容
});
//监听端口
app.listen(80);
//打印提示文字
console.log('服务器启动完成');

get参数

Express框架中使用request.query即可获取get参数,框架内部会将get参数转换为对象返回。

app.get('/index', (request, response) => {
    //request.query获取get参数
    let data = request.query;
    console.log(data);
    response.send('OK');
});

post参数

Express中接收post请求参数需要借助第三方body-parser。

//引入模块
const express = require('express');
const bodyParser = require('body-parser');
//创建服务器,并且获取服务器对象
const app = express();
//拦截所有请求,通过bodyParser模块对象下的urlencoded方法解析post参数
app.use(bodyParser.urlencoded({ extended: false }));//extended: false代表是否不使用Node系统内置的querystring对象解析post参数,true则是使用第三方模块qs,false则使用querystring
app.post('/add', (request, response) => {
    console.log(request.body);//经过拦截所有请求,解析post参数后,request形参就多了一个body属性,这个body属性就是post参数对象的形式
});
//监控端口
app.listen(80);
//打印提示文字
console.log('服务器启动成功');

注意事项:
bodyParser.urlencoded({ extended: false })的返回值是一个函数,这样就相当app.use()方法中传递了一个函数。

Express路由参数

//引入模块
const express = require('express');
//创建服务器,并且获取服务器对象
const app = express();
//添加路由,/index/:id中的:id表示希望客户端传递以地址形式传递一个id参数
app.get('/index/:id', (request, response) => {
    //request.params Express框架中提供获取路径参数的方法,返回值是对象形式的
    response.send(request.params);
});
//监控端口
app.listen(80);
//打印提示文字
console.log('服务器启动成功');

注意事项:
这样做的优点是优化路径,提升美观。
示例:'/index/:id/:name/:age',
客户端地址:'http://loaclhost:80/index/12345678/zhangsan/18',
服务器获取参数:'{id:12345678,name:zhangsan,age:18}'

静态资源访问

通过Express内置的express.static可以方便地托管静态文件。例如img、CSS、javascript文件等…

//引入模块
const express = require('express');
const path = require('path');
//创建服务器,并且获取服务器对象
const app = express();
//拦截所有请求,调用express对象下static方法托管静态资源
//express.static('路径地址')
app.use(express.static(path.join(__dirname, 'public')));
//监控端口
app.listen(80);
//打印提示文字
console.log('服务器启动成功');

注意:
上述拦截了所有请求,进行判断是否为静态资源,在进行访问资源。但也不必拦截所有请求,也可以指定特定路径。

模板引擎

为了使art-template模板引擎能够更好的和Express框架配合,模板引擎官方在原art-template模板引擎的基础上分装了express-art-template。

使用命令:npm install art-template express-art-template

//引入模块
const express = require('express');
const path = require('path');
//创建服务器,并获取服务器对象
const app = express();


//指定后缀为.art的使用express-art-template模板渲染
//app.engine('后缀名称', 指定模板);
app.engine('art', require('express-art-template'));
//指定模板文件夹
//app.set('views', 模板文件夹地址);,views是模板配置属性名(固定)
app.set('views', path.join(__dirname, 'views'));
//设置模板文件默认后缀名
//app.set('view engine', '后缀名');
app.set('view engine', 'art');


//创建路由
app.get('/', (request, response) => {
    //响应拼接后的模板文件
    // response.render('模板名称', {需要拼接的模板数据对象});
    response.render('index', {
        msg: 'message'
    });
});
//错误处理
app.use((error, request, response, next) => {
    response.status(500).send(error);
    next();
});
//监听端口
app.listen(80);
//打印提示文字
console.log('服务器启动成功');

服务器对象.locals

将变量设置到app.locals对象下面这个数据在所有模板下都可以获取。

app.locals.属性名称 = {};//在app.locals对象下添加属性

URL

统一资源定位符,是Interent网上资源位置而设定的编址方式。

本机域名:localhost

本地IP:127.0.0.1

URL组成

传输协议://服务器IP或者域名:端口/资源所在位置标识符

服务器

Node网站服务器概念

能够提供网站访问服务的机器就是网站服务器,它能够接受客户端的请求,并作出相对应的响应

Node.js创建Web服务器

一、创建网站js代码
// 一、引入http模块,http用于创建Web服务器的模块
const http = require('http');
// 二、createServer创建Web服务器,返回值为Web服务器对象
const app = http.createServer();
// 三、给Web服务器对象添加(反应)事件,request客户端请求时,调用该处理函数。
app.on('request', (request, response) => {
    response.end('<h2>hi!</h2>');
});
/*
app.on(事件名称,处理函数);
app.on(事件名称,function(请求对象,响应对象) {

});
*/
// 四、监听端口
app.listen(3000);
/*
app.listen(端口号);//监听指定端口
*/
console.log('网站服务器启动成功!');//文件启动时的提示

二、执行js文件
在命令行输入:node js文件名称

三、测试
在本地输入网址:localhost:端口号,访问本地服务器。

HTTP协议

概述

HTPP(超文本传输协议)规定了如何从网站服务器传输超文本到本地浏览器,它是基于客户端架构工作,是客户端(用户)和服务器(网站)请求和应答的标准。

报文

在HTTP请求和响应的过程中传输的数据块叫做报文,包括了传送的数据和一些附加信息,并且要遵守规定好的格式。

请求报文

请求方式:

  • GET 请求数据
  • POST 发送数据
html中表单报文方式(一般为POST提交数据)
<!-- 
	method:表单提交方式->报文方式
	1POST:数据提交(发送)
	2GET:数据请求
	action:表单数据的提交地址
-->
<form method="POST" action="http://localhost:3000">
	<label for="">账号:</label><input type="text" name="ures"><br>
	<label for="">密码:</label><input type="password" name="password" id=""><br>
<input type="submit" value="提交">
</form>
Node的HTTP模块
HTTP模块事件响应中请求对象
const http = require('http');//引用http模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
	let 变量名 = 请求对象[或者响应对象].method;//报文方式
    let 变量名 = 请求对象[响应对象].url;//获取请求地址
    let 变量名 = 请求对象[响应对象].headers;//获取请求报文
    let 变量名 = 请求对象[响应对象].headers['属性名'];//获取请求报文中指定属性的值
});
app.listen(端口号);//监控端口
响应报文
HTTP状态码
  • 200:请求成功
  • 301:重定向
  • 404:请求的资源没有被找到
  • 500:服务器端错误
  • 400:客户端请求有语法错误
const http = require('http');//引用http模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
	响应对象.writeHead(状态码);//修改状态码
});
app.listen(端口号);//监控端口
内容类型
  • text/html
  • text/css
  • application/javascript
  • image/jpeg
  • application/json
const http = require('http');//引用http模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
	响应对象.writeHead(状态码,{
        响应头部信息;//以对象形式书写
        'content-type':'text/plain;charset=utf8'//text/plain纯文本,charset=utf8指定字符集(分号相隔)
    })
});
app.listen(端口号);//监控端口
头部信息

Location:通过方法writeHead()修改头部改变URL位置(一般用于网页跳转)。

URL模块[GET]

功能:URL模块可以解析请求对象的url地址。

const http = require('http');//引用http模块
const url = require('url');//引用url模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
	let url = url.parse(请求对象.url,布尔值(是否将返回值以对象形式返回));
});
app.listen(端口号);//监控端口

POST

POST是通过事件的形式接收的。

data:当请求参数传递时触发data事件。

end:当请求数据传递完毕时触发end事件。

注意:由于POST数据一定一次接收完毕,所以才会有data事件和end事件。

示例
const http = require('http');//引用http模块
const url = require('url');//引用url模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
	请求对象.on('data(事件名称)',function(数据片段(拼接在一起即可使用)) {//当数据(参数)传输时,触发
        
    });
    请求对象.on('end',function() {//当数据(参数)传输完毕时,触发
        处理过程;
    });
});
app.listen(端口号);//监控端口

querystring

通过以上步骤就可以获取用户发送过来的数据(参数),但是是一个字符串,需要处理。node.js中提供了querystring内置模块处理该字符串。

使用
let uesrData = querystring.parse(formData);
分析:
1.querystring.parse()将字符串解析成对象形式
2.将formData字符串解析成为对象形式,方便后续操作
示例
const http = require('http');//引用http模块
const url = require('url');//引用url模块
const querystring = require('querystring');//引入querystring模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
    let paramsPost = '';//创建储存POST数据包的变量
	请求对象.on('data',function(params;) {//当数据(参数)传输时,触发
        paramsPost += params;//拼接数据片段
    });
    请求对象.on('end',function() {//当数据(参数)传输完毕时,触发
        var dataPost = querystring.parse(paramsPost);//解析数据包,将其转换成为对象形式,以便操作。
    });
});
app.listen(端口号);//监控端口解析POST数据包

路由

概述

路由是指客户端请求地址与服务器程序代码之间的关系。简单来说就是客户端想要什么资源就给什么

资源即可。

资源

静态资源

服务器不需要处理,可以直接响应给客户端的资源就是静态资源。

动态资源

相同的请求地址不同的响应资源,这种资源就是动态资源。

MongoDB数据库

安装

百度自查

开始服务

net start moogodb//开启服务
net stop moogodb//关闭服务

数据类型

名词说明
Number数值型
String字符串
Date时间型

数据库相关概念

术语说明
database数据库,MongoDB数据库软件可以创建多个数据库
collectior集合,一组数据的集合,可以理解为JavaScript中的数组
document文档,一条具体的数据,可以理解为JavaScript中的对象
field字段,文档中的属性名称,可以理解为JavaScript中的对象属性

使用

node.js如果想使用MongoDB数据库需要下载第三方模块:MongoDB

连接数据库
1.在命令行中使用命令:
npm install mongoose

2.在js文件中引入mongoose模块:
const mongoose = require('mongoose');

3.创建数据库链接:
mongoose.connect('mongodb://链接地址url:端口/数据库名称', { useNewUrlParser: true, useUnifiedTopology: true }) 
//创建连接,连接数据库
//useNewUrlParser:使用新的URL解析器,useUnifiedTopology:使用使用统一的表学
    .then(function() { //连接成功时:处理函数
        console.log('数据库连接成功!');
    })
    .catch(function(错误信息error) { //连接失败时:处理函数
        console.log('数据库连接失败!', error);
    });

注意:
MongoDB数据库默认的端口为:27017
创建数据库

在MongoDB中不需要显示创建数据库,如果正在使用的数据库不存在,MongoDB会自动创建

创建集合

创建集合分为两步,一是对集合设定规则,二是创建集合。

//(一)引入mongoose模块
const mongoose = require('mongoose');

//(二)连接数据库
mongoose.connect('mongodb://localhost/databaseName', { useNewUrlParser: true, useUnifiedTopology: true }) 
    .then(function() { //连接成功时:处理函数
        console.log('数据库连接成功!');
    })
    .catch(function(error) { //连接失败时:处理函数
        console.log('数据库连接失败!', error);
    });

//(三)创建集合
// 1.创建集合的规则(所有字段或者集合属性)
let schema = new mongoose.Schema({ 
    //1.创建模式对象(集合规则),通过构造函数添加字段规则
    //2.返回值模式对象(集合规则)对象
    name: String,
    author: String,
    isCourseOpen: Boolean
    //(字段名称:字段数据类型)
});
// 2.使用集合规则创建集合
let 构造函数名称 = mongoose.model('Course', schema); 
//1.创建集合,实际上它在创建集合名时会添加s结尾,此案例为:courses
//2.model()创建集合之后,会返回一个集合的构造函数。

注意:
已经创建数据库和集合而没有数据时,数据库中不会显示。
创建文档
//(一)引入mongoose模块
const mongoose = require('mongoose');

//(二)连接数据库
mongoose.connect('mongodb://localhost/databaseName', { useNewUrlParser: true, useUnifiedTopology: true }) 
    .then(function() {
        console.log('数据库连接成功!');
    })
    .catch(function(error) {
        console.log('数据库连接失败!', error);
    });

//(三)创建集合
let schema = new mongoose.Schema({ 
    name: String,
    author: String,
    isCourseOpen: Boolean
});
let Course = mongoose.model('Course', schema); 

//(四)创建文档:方法一
let document = new Course({ //创建文档,构造函数中传递以对象的形式文档内容
    name: '小美的上分之路',
    author: '陈主任',
    isCourseOpen: false
	//(字段名称:字段值)
});
document.save(); //保存数据

//方法二
Course.create({字段数据内容}, 回调函数(错误信息,结果信息【以对象形式返回】));//create()方法返回的也是Promis对象

Course.create({//使用Course集合构造函数中的creat方法创建文档
    name: '关于我是大帅逼的自我修养',
    author: '黑人的乔丹鞋',
    isCourseOpen: true
	//构造函数中传递以对象的形式文档内容(字段名称:字段值)
}, function(error, result) {//回调函数(错误信息,结果信息【以对象形式返回】){}
    console.log('错误信息:', error);
    console.log('结果:', result);
});
mongoDB数据库导入数据
mongoimport -d 数据库名称 -c 集合名称 --file 要导入的数据文件
注意:
1.新版mongoDB数据库将这类型功能分离了出去,需要单独下载,解压到mongoDB根目录下[详细方法请百度]
2.执行该指令前需要在系统环境变量path中添加mongoDB根目录
查询数据(文档)
等于
//(一)find()
集合构造函数对象.find().then().catch();
//1.find()方法返回值是一个Promis对象,也就是说可以使用then()和catch()方法。
//2.find()方法的返回值结果是一个数组,查询的数据条数不会影响。
//3.find()方法如果没有参数传递的话,那么默认查询集合中所有文档
集合构造函数对象.find({
    查询条件
    //'字段名称':字段值
}).then().catch();

//(一)findOne()
集合构造函数对象.findOne().then().catch();
//1.返回值为对象
//2.当没有参数传递时,默认返回第一条文档数据。
小于、大于
集合构造函数对象.find(字段名:{$gt:1,$lt:2}).then().catch();
//字段名:条件(条件值为对象形式传递){
$gt:1,
$lt:2
//大于值1,小于值2
}
//$gt:大于
//$lt:小于(这是固定语法)

示例:
User.find({ 'age': { $gt: 18, $lt: 40 } }).then(res => console.log(res));//查询User集合中字段age大于18小于40的文档
包含
集合构造函数对象.find(字段名:{$in:['值']}).then().catch();
//$in包含某字符,条件值为数组形式传递

示例:
User.find({hobbies: { $in: ['敲代码'] }}).then(result => console.log(result));//查询User集合中字段名hobbies包含敲代码的文档。
查询字段
集合构造函数对象.find().select('字段名 -字段名').then().catch();
//1.字段名之间使用空格隔开
//2.不想显示的字段前加-,如:-_id不显示_id字段
排序
集合构造函数对象.find().sort('字段名').then().catch();
//1.sort()方法按照指定字段名排序,默认升序
//想要降序排名,在字段名前加-,如:-age按降序排列age字段

跳过、限制

集合构造函数对象.find().skip().limit().then().catch();
//skip()跳过指定条文档
//limit()限制指定条文档显示
删除文档
删除单个文档
集合构造函数对象.findOneAndDelete(条件(以对象形式传递).then().catch();

User.findOneAndDelete({'_id': '5c09f2d9aeb04b22f846096b'}).then(res => console.log(res));
//删除User集合中_id为5c09f2d9aeb04b22f846096b
删除多个文件
集合构造函数对象.deleteMany(条件(以对象形式传递)).then().catch();
//如果不传递参数或者传递空参数,它默认会删除集合中所有文档。
//deleteMany()方法返回一个对象,包含删除文档个数、执行状况等信息
更新文档(修改)
更新单个文档
集合构造函数对象.updateOne({查询条件},{修改条件}).then().catch();
//更新单条文档,如果同时多条文档瞒住,值修改查询到的第一条文档。
更新多个文档
集合构造函数对象.updateMany({查询条件}, {修改条件}).then().catch();
//查询条件为空,则是修改集合中所有文档

mongoose验证

在创建集合规则时,可以设置当前字段的验证规则,验证失败就不允许插入数据。

  • required:true 必传字段(类似于MySql中的主键)
  • minlength:数字型值【限定字符串最小长度】
  • maxlength:数字型值【限制字符串最大长度】
  • min:数值型使用,限制数字大小。
  • max:数值型使用,限制数字大小。
字段值对象验证属性
属性使用说明
type类型
required必传字段
minlength字符串最小长度限制
maxlength字符串最大长度限度
min数值型最小值限制
max数值型最大型限制
enum{values:指定元素数组,message:‘错误信息’}枚举,只能是包含之中的元素才可以输入进指定字段
validatevalidate:{validator:function(value) {函数体},message:‘错误信息’}检验,以对象形式添加规则,其中有个属性validetor(处理函数(值value))检验器,配合使用
unique唯一
在创建集合规则时,给字段添加验证
let 变量名 = mongoose.Schema({
    //字段名:字段值
    title:{
        type:String,//说明这个字段是String类型数据
        required:true //将required属性设置为true,说明该字段为必传字段
        required:[true,'自定义错误信息']//属性值可以是数组类型,第二个元素为自定义错误信息
    }
});

示例:
let articleSchema = mongoose.Schema({ //创建集合规则
    title: {
        type: String,
        required: [true, '请输入文章标题'], //限制条件
        minlength: [2, '您输入的标题不能低于2个字符!'],
        maxlength: [5, '您输入的标题不能高于5个字符!'],
        unique:true//保证数据唯一
    }
    age: {
        type: Number,//数值型
        min: 1,//最小值1
        max: 100//最大值100
    },
    publicshDate: {
        type: Date,//时间型
        default: Date.now//Date.now获取当前时间,default默认值。
	subject:{
		type:String,//字符串类型
		enum:['java','javascript','html','css']//枚举,存储的subject字段必须是其中之一。
	},
	author:{
		type:String,//字符串类型
		validate:{//检验
			validator:value => {//检验器
				return value && value.length > 4
			},
			message:'不满足自定义条件'//错误输出信息
		}
	}
});

let Article = mongoose.model('Article', articleSchema); //使用集合规则创建集合
Article.create({字段名:字段值})
    .then(reslut => {
	//打印正确时返回值
		console.log(reslut);
    })
    .catch(error => {
        //获取错误信息对象
        const err = error.errors;
        //for对象内容,打印出关键错误信息
        for (var attr in err) {
            console.log(err[attr]['message']);
        }
    }); //使用create()方法创建文档
打印错误信息

在增、删、改、查时打印主要的错误信息,可以使用.catch()方法参数error错误对象,获取其中的errors对象。遍历该对象,打印其中的message消息(这个消息一般就是我们自定义的错误信息了)。

集合关联

概述

通过不同集合的数据之间是有关系的。例如文章内容和用户信息存储在不同集合。但文章是某个用户发表的,要查询文章的所有信息包括发表用户,就需要关联。

使用

1.在集合限制条件下创建关联

type: mongoose.Schema.Types,//type类型:mongoose.Schema.Types(固定)
ref: 'user'//ref关联集合

2.使用关联

populate()方法查询关联字段
集合.find().populate('关联字段名').then(result => console.log(result)).catch();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值