node和express框架的基础入门

NODE在真实项目中的应用

node 的特点:

  • 基于v8(webkit内核)引擎渲染和解析js (所以它非后台语言是一个工具或环境,用来解析js的工具或环境 )(类似:webview/谷歌浏览器等)

    1.基于命令$ node xxx.js 把js代码在node环境里执行。
    2.基于REPL模式(Read-Evaluate-Print-Loop,输入-求值-输出-循环)$ node

  • 基于node.js(JavaScript)实现服务器端的功能操作
    node和express框架的基础入门_第1张图片

    node和express框架的基础入门_第2张图片

node和express框架的基础入门_第3张图片


简述NODE和浏览器运行js的区别

NODE的特点:

  • 单线程,无阻塞I/O操作,event-driven事件驱动

I/O

I/O :一般指对文件的读写操作
I :input 输入
O:output 输出

在客户端浏览器中运行
1,不能对客户端本地文件进行读写操作,因为要保证客户端安全。
2,input:type='file’文件上传这种除外,但是也要用户手动选择后才可以。

在服务端运行(基于NODE运行)
1,可以对服务端文件进行读写操作
2,NODE赋予了JS进行I/O操作的能力(内置模块:fs)

window & global

在客户端浏览器中运行JS
JS的全局对象是:window(提供了很多内置的属性和方法)

在NODE中运行JS
JS的全局对象是:global

  • process:node中进程管理的属性
  • Buffer
  • setImmdeiate 立即执行(类似于setIimeout(func,0))

NPM的使用

模块管理(安装和卸载)

安装在全局环境下和安装在当前项目中

  • 安装在全局:$ npm install xxx --global ( $ npm I -g xxx)**

  • 安装在本地项目中: $ npm install xxx
    {
    把模块设置为开发依赖(开发中):$ npm install xxx --save-dev
    把模块设置为生产依赖(部署到服务器):$ npm install xxx – save
    }

  • 安装在全局和本地的区别
    {
    在全局:安装在全局对任何项目都有作用(也有可能导致版本冲突),但是只能基于命令的方式管理,不能基于CommonJS中的require导入使用。($ npm root -g 查看全局安装到目录,原因是在全局目录下生成了一个 xxx.cmd的文件)
    在本地:默认不能基于命令管理,但是可以导入到文件中基于代码操作只对当前项目有用
    }

  • 在本地安装模块之前,这样最好先 $ npm init -y,生成package.json模块配置文件

    把安装的模块生成配置请单,存放在package.json中,后期别人需要部署文件的时候,只需执行 $ npm i 就可以把所以的依赖项重新安装一遍 。(“跑环境”)

        $ npm i :是把开发和生产依赖的模块都安装一遍
        $ npm I --production :只安装生产依赖的模块
    

在package.json 中,可以基于scripts选项配置本地可执行的脚本命令 $ npm run xxx :

"scripts":{
	// AAA是命令,值是要做的事
	"AAA": "node xxx.js",
}

在配置可执行脚本命令的时候,基于process的环境变量区分开发还是生产环境

"scripts":{
	// set NODE_EVN=dev  设置全局环境变量 ( mac下用 export NODE_EVN=dev )
	"serve":"set NODE_EVN=dev&&node text1.js",
	"built":"set NODE_EVN=pro&& node text1.js"
	}

NODE中的CommonJS模块管理机制

常用的模块管理机制

   AMD:require.js
   CMD: sea.js
   CommonJS: node.js
   ES6: Module

这些模块化思想,规定了在JS中我们的模块如何创建,如何导入及如何导出。

内置模块:NODE中自带的
  http/https     创建和管理服务的模块
  fs     给予JS进行I/O操作的
  url     解析URL地址的
  path     管理路径的
  ...
第三方模块:基于npm安装,别人写好供我们使用的
     less
     mime
     qs
     express 
     express-session
     body-parser
     ...
自定义模块:自己写的模块

NODE中的模块管理

  1. 在NODE环境下,我们每创建一个JS,都相当于创建了一个新的模块;
    模块中的方法也都是模块私有的方法,不同模块之间的同名方法不会有任何冲突;
  2. module.exports 就是NODE天生自带的用来导出模块中的方法
module.exports={
   //这些属性的方法就是需要暴露给外面调取使用的
   xxx:xxx
}; 
  1. require是NODE天生提供用来导入模块的方法
//语法
let[模块名] = require([模块的地址])
let A = require('./A')
let qs = require('qs')

// 1)可以省略.js
// 2)如果是调取自己定义的模块,则需要加/(根目录)./(当前目录)../(上级目录)这三个中的某一个
// 3)不加上述地址,则先找第三方模块(安装在自己本地的),如果没有,则找NODE中的内置模块,如果再没有,则报错。
  1. 导入模块是同步的(没导入完成,后面的事情不处理);每一次导入模块都是吧导入的模块中的JS代码从上到下执行一遍(只执行一遍)

FS模块中常用的方法

fs 内置模块

fs全称是file system(文件系统),它是NodeJS提供的文件操作API。
提供大量的属性和方法,让JS在NODE环境中执行的时候,可以操作服务器的资源文件,也就是给予了I/O操作的能力

  • readdir / readdirSync :异步或者同步读取指定目录下的文件目录
// 读取指定目录(相对目录和绝对目录都可以)中的文件目录
let result = fs.readdirSync('./')
console.log(result);

//异步操作是:读取成功后触发回调函数执行
fs.readdir('./',(err,result) =>{
   // => ERR 存储读取失败后的错误信息
   // => RESULT 存储读取成功后的结果(此时ERR=NULL)
   if(err === null){
   	console.log(result);
   }
});
  • readFile : 同步或者异步读取某一个文件中的内容
    不设置编码格式,默认得到的是Buffer流(编码)格式的数据,设置utf-8,得到的结果是字符串(例如:JSON格式,HTML格式或者CSS格式)
    但是对于富媒体资源(例如:图片,音频等)我们读取和传输的过程中就是基于BUFFER文件流格式操作的
// 语法
let result = fs.readFileSync('[path]','[encoding]')
//异步操作
fs.readFileSync('[path]','[encoding]','callback')

/* 例如
fs.readFile('./',‘utf-8’,(err,result) =>{
	if(err === null) return;
	console.log(result);
	});
*/
  • writeFile : 同步或者异步写取某一个文件中的内容
    向某个文件中写入内容(如果文件不存在,他会默认创建一个文件再写入,而且写入的方式是“把之前文件中的内容全覆盖”)

  • copyFile:把某个文件里面的内容拷贝到新的目录中
    替换型拷贝:原来目录中存在这个文件,新拷贝的会替换原来的

fs.copyFile('./A.txt','./c.txt',err ={
	console.log(err);
})
  • mkdir:创建目录
fs.mkdir('./js',err ={
	console.log(err);
})
  • rmdir 删除目录
    要保证目录中不再有文件,否则不让删除
fs.rmdir('./js',err ={
	console.log(err);
})

fs文档


PROMISE版FS的封装

封装fs模块的所有api返回一个promise对象使之能够实现链式操作,避免回调地狱。

let fs=require('fs'),
	path = require('path')
	
function readFile(pathname){
	//获取文件的后缀名
	let suffixREG = /\.([0-9a-zA]+)$/,
		suffix = suffixREG.test(pathname)?suffixREG.exec(pathname)[1]:'',
		encoding = 'utf-8';
	/^(PNG|GIF|JPG|JPEG|WEBP|BMP|ICO|SVG|MP3|MP4|WAV|OGG|M3U8)$/i.text(suffix)?
	//=> 用户调用的时候,传递的PATH-NAME都以项目根目录作为参照(执行JS也是在根目录执行),用户只需要把读取文件,相对根目录的路径和名称传递进来即可
	
	pathname = path.resolve(pathname);
	return new Promise((resolve,reject)=>{
		fs.readFile(pathname,encoding,(err,result)=>{
			if (err !== null){
			reject(err);
			return;
			}
			resolve(result);
		}) 
	})
}

module.exports ={
	readFile
	}
let{
	readFile
	} = require('./utils/promiseFS');

readFile('./js/path/js').then(result =>{
	console.log(result);
	}).catch(reason =>{
		console.log(reason);
	});
	

基于FS完成CSS合成并压缩

  • 合并css的步骤
    1,读取css目录中所有文件,最后找到后缀名是.css的
    2,依次读取css文件中的内容,最后吧所有内容合并在一起
    3,把合并后的结果放到DIST文件夹中的index.css文件夹中
let{
	readdir,
	readFile,
	mkdir,
	writeFile
	} = require(./)

readdir('.css').then(result =>{
	result = result.filter(item => /\.css$/i.text(item));
	result = result.map(item =>{
		return readFile('./css/${result[item]}')
		})
	
	return Promise.all(result);
}).then(results =>{
	results = results.join('');
	// 此时的results存储的是未经压缩的合并后的css代码,接下里基于less模块完成css内容的压缩
	return new Promise((resolve,reject)=>{
		less.render(results,{
			// less模块规定:设置压缩的方式
			compress:ture
		},(err,result)=>{
			if(err !== null) reject(err);
			resolve(result.css);
		});
	});
	

}).then((css) =>{
	//把压缩后的写在指定的目录中
	return wrieFile('./dist/index.css',css);
	console.log('创建成功')})

HTTP内置模块和服务创建

url 内置模块

  • url.parse()用来解析url中每一部分信息
    第二个参数传ture,自动会把问号参数解析成键值对的方式,存储在query属性中
  • query:问号传递参数的键值对
  • pathname:请求路径名称

服务器端要做的常规任务

  1. 首先想干事需要有一个服务(创建服务:)
  2. 接受客户端的请求信息(请求静态资源文件,数据)
  3. 查找到对应资源文件内容或对应的数据信息
  4. 把找到的内容返回给客户端
let http = require('http')
	url = require('url')

// http.create-server 创建服务
let server = http.createServer();

//当客户端向当前服务发送请求的时候,会触发此回调函数(请求N次,回调执行n次)而且每一次都能获得本次请求的相关信息。
//req:request req对象中存储了客户端的请求信息
//res:respomse res对象提供了对应的属性和方法,可以让服务器返回给客户端信息

//server.listen监听端口号
/*server.listen(80,()=>{
    //当服务创建成功,并端口号已经监听完成,触发此回调函数执行
    console.log('服务已经给予post端口启动')
    })*/
let PORT=80function listen(PORT){
	try{
		server.listen(80,()=>{
    	console.log('服务已经给予post端口启动')
    	 });
	} catch(err){
		PORT++;
		listen(PORT);
	}
}
listen(PORT)

EXPRESS基础语法

request对象(req)

  • req.path:存储请求地址的路径名称
  • req.query:存储问号传参的相关信息(对象)
  • req.body:在配合body-parser中间件的情况下,req.body存储的是请求主体传过来的信息
  • req.method:请求方式
  • req.get:获取响应头信息

response对象(res)

  • res.end:类似于原生的操作,结束响应并返回内容
  • res.json:返回给客户端内容,只不过传递的数据可以是json对象(内部会帮我们把其转化为json字符串 =>服务返回给客户端的内容一般都是字符串或者buffer格式)
  • res.send:最常用的给客户端返回信息(可传递对象path/buffer/txt等),基于send是通过响应主体返回给客户端信息
  • res.status:返回状态码
  • res.type:返回content-type的类型值
  • res.set:设置响应头信息 res.set([key],[value])
let express = require('express');

// 执行express创建一个服务:返回的结果app用来操作这个服务
// app.listen:创建一个web服务,监听端口号
let app = express();
app.listen(8080,()=>{
    console.log('server successfully!')
});

// 静态资源文件的请求处理
//express.static([path]):指定的目录中查找客户端需要的资源文件内容,并且将其返回
app.use(express.static('./client'));
app.use((req,res)=>{
    //执行static没有找到对应资源文件(可以做404处理)
    res.status(404);
    res.send('NOT FOUND!')
})

EXPRESS中的数据处理和中间件

中间件:在创建完服务和处理数据(文件)请求之前,我们提前做一些事情(公共的事情)

app.use([path],function)
path:是路由的url,默认参数‘/’,意义是路由到这个路径时使用这个中间件
function:中间件函数(function(request,response,next))

  • express-session
    是express中的一个处理session的中间件,可以说是express中最常见的中间件之一了.

  • body-parser

    • body-parser是一个HTTP请求体解析的中间件,使用这个模块可以解析JSON、Raw、文本、URL-encoded格式的请求体.

    • body-parser还支持为某一种或者某一类内容类型的请求体指定解析方式,指定时可以通过在解析方法中添加type参数修改指定Content-Type的解析方式。
      比如,对text/plain内容类型使用JSON解析

    • body-parser模块的API
      当请求体解析之后,解析值会被放到req.body属性中,当内容为空时候,为一个空对象{}
      bodyParser.json()–解析JSON格式
      bodyParser.raw()–解析二进制格式
      bodyParser.text()–解析文本格式
      bodyParser.urlencoded()–解析文本格式


EXPRESS项目整体框架和路由结构

let express = require('express');
    bodyParser = require('bodyParser')
    promiseFS = require('./promise')
let{
	dataHandle
} = require('./utils')

//创建web服务
app.listen(8080,()=>{
    console.log('server successfully!')
});

//数据接口API的请求处理
//把post请求基于主体传递的信息获取到,放到req,body上
app.use(bodyParser.urlencoded({
    extended:true
}));
//把json文件中所以存储的数据都获利,放到req.xxx上
app.use((req,res,next)=>{
	let path = './json';
	let p1 = promiseFS.readFile(path + '/user.json'
    let p2 = promiseFS.readFile(path + '/customer.json'
    let p3 = promiseFS.readFile(path + '/visit.json'
    let p4 = promiseFS.readFile(path + '/department.json'
    let p5 = promiseFS.readFile(path + '/job.json'
    Promise.all([p1,p2,p3,p4,p5]).then(resqults =>{
    	let[$USERDATA,$CUSTOMERDATA,$VISTDATA,$DEPARTMENTDATA,$JOBDATA] = results;
    	req.$USERDATA = dataHandle($USERDATA);
    	req.$CUSTOMERDATA = dataHandle($CUSTOMERDATA);
    	req.$VISTDATA = dataHandle($VISTDATA);
    	req.$DEPARTMENTDATA = dataHandle($DEPARTMENTDATA);
    	req.$JOBDATA = dataHandle($JOBDATA);
       	next();
    	
    }).catch(err =>{
    	res.status(500);
    	res.send(err);

	})
})
//构建EXPRESS路由
//请求的API地址符合xxx的,都进入到指定的路由中
app.use('/user',require('./routes/user'));
app.use('/customer',require('./routes/customer'));
app.use('/visit',require('./routes/visit'));
app.use('/department',require('./routes/department'));
app.use('/job',require('./routes/job'));
 
//静态资源文件的请求处理
app.use(express.static('./client'));
app.use((req,res)=>{
    res.status(404);
    res.send('NOT FOUND!',)
})
// 把json字符串转化Json对象,并且过滤掉STATE===1的
function dataHandle(str){
	let arr =JSON.parse(str);
	arr =arr.filter(item =>{
		return parseInt(item.state)===0;
		});
		return arr;
}

module.exports ={
	dataHandle
};

你可能感兴趣的:(node和express框架的基础入门)