一、概念

1.什么是nodejs
  • Node.js是JavaScript 运行时环境,通俗易懂的讲,Node.js是JavaScript的运行平台
  • Node.js既不是语言,也不是框架,它是一个平台
2.nodejs特点
  • 没有Bom,Dom
  • 在Node中这个JavaScript执行环境为JavaScript提供了一些服务器级别的API
    • 例如文件的读写
    • 网络服务的构建
    • 网络通信
    • http服务器
  • 构建在Chrome的V8引擎之上,意味着nodejs的执行效率很高
  • 基于事件驱动envent-driven ,non-blocking I/O mode 非阻塞I/O模型(异步)ightweight and efficent. 轻量和高效
  • 包含NPM包管理器,npm 是世界上最大的开源生态系统,绝大多数JavaScript相关的包都存放在npm上,这样做的目的是为了让开发人员更方便的去下载使用
3.nodejs可以做什么
  • web服务器后台
  • 命令行工具,执行npm命令等
  • 借助npm包管理器构建项目,和上传自己的组件

二、安装和使用

到官网下载Node,并一路next就能完成安装,如果安装过后再次安装新版本则会自动升级安装。官网:https://nodejs.org/en/

确认是否安装成功,输入以下命令查看版本号:

node --version

配置目录

在nodejs安装目录创建【node_global】及【node_cache】两个文件夹

创建完两个空文件夹之后,打开cmd命令窗口,输入

npm config set prefix "D:\Develop\nodejs\node_global"
npm config set cache "D:\Develop\nodejs\node_cache"

接下来设置环境变量,关闭cmd窗口,“我的电脑”-右键-“属性”-“高级系统设置”-“高级”-“环境变量”

进入环境变量对话框,在【系统变量】下新建【NODE_PATH】,输入【D:\Develop\nodejs\node_global\node_modules】

将【用户变量】下的【Path】修改为【D:\Develop\nodejs\node_global】

三、核心API的使用

Global 全局对象

Global是node.js的全局对象,使用它里面的属性或方法或子对象,可以不用加global

例如

global.console.log('你好');

**另外:**这些对象在所有的模块中都可用。 以下的变量虽然看似全局的,但实际上不是。 它们仅存在于模块的作用域中

console.log('Dirname:',__dirname);
console.log('Filename:',__filename);
console.log('Exports:',exports);
console.log('Module:',module);
console.log('require:',require);

打印结果:

Dirname: F:\vue_project\learn_nodeJs\src\01-NodeJs初步使用
Filename: F:\vue_project\learn_nodeJs\src\01-NodeJs初步使用\5-全局变量.js
Exports: {}
Module: Module {
id: '.',
path: 'F:\\vue_project\\learn_nodeJs\\src\\01-NodeJs初步使用',
exports: {},
parent: null,
filename: 'F:\\vue_project\\learn_nodeJs\\src\\01-NodeJs初步使用\\5-全局变量.js',
loaded: false,
children: [],
paths: [
'F:\\vue_project\\learn_nodeJs\\src\\01-NodeJs初步使用\\node_modules',
'F:\\vue_project\\learn_nodeJs\\src\\node_modules',
'F:\\vue_project\\learn_nodeJs\\node_modules',
'F:\\vue_project\\node_modules',
'F:\\node_modules'
]
}
require: [Function: require] {
resolve: [Function: resolve] { paths: [Function: paths] },
main: ...,//省略内容
extensions: ...,//省略内容
cache: ...,//省略内容
}
1.fs模块的使用

浏览器中的JavaScript是没有文件操作能力的,但是Node中的JavaScript具有文件操作能力,在Node中如果想要进行文件的操作就必须引用fs这个核心模块。fs模块提供了了所有文件操作相关的API

下面是一些基本的代码示例:

1.1文件读取
//  1.使用fs核心模块
var fs = require('fs'); /**
* filename, 必选参数,文件名
* [options],可选参数,可指定flag(文件操作选项,如r+ 读写;w+ 读写,文件不存在则创建)及encoding属性
* callback 读取文件后的回调函数,参数默认第一个err,第二个data 数据
*/
fs.readFile('./data/a.txt',function(err,data){
if(err){
console.log('文件读取失败');
}
else{
console.log(data.toString());
}
}) // readFileSynsc();同步操作a也是就是说会等当前执行完后在,才会输出2,(阻塞)
let data = fs.readFileSync('./text.txt');
console.log(data.toString())
console.log(2);
1.2文件写入
//  1.使用fs核心模块
var fs = require('fs'); /**
* filename, 必选参数,文件名
* data, 写入的数据,可以字符或一个Buffer对象
* [options],flag,mode(权限),encoding
* callback 读取文件后的回调函数,参数默认第一个err,第二个data 数据
* 文件不存在则会自动创建一个文件
*/
fs.writeFile('./data/a.txt','我是文件写入的信息',function(err){
if(err){
console.log('文件写入失败');
}
}) // 同步版本的写入
fs.writeFileSync('./2.text','我是同步写入的文件')
1.3以追加方式写文件
let fs = require('fs');
/*
* 追加文件内容
* */
fs.appendFile('../data/a.txt', '\n使用fs.appendFile追加文件内容', function (error) {
if(error){
console.log('追加文件内容出错');
}else {
console.log('追加内容完成');
} }); // 同步方式
// fs.appendFileSync('../data/a.txt','追加的内容');
1.4创建文件目录
let fs = require('fs');

/**
* fs.mkdir(path, [mode], callback);
* path, 被创建目录的完整路径及目录名;
* [mode], 目录权限,默认0777
* [callback(err)], 创建完目录回调函数,err错误对象
*/
fs.mkdir('../data/test1',function (error) {
if(error){
console.log('创建文件夹失败');
}else {
console.log('创建文件夹成功');
}
}); /*
* 同步方法
* */
fs.mkdirSync('../data/test2');
1.5读取文件目录
// 异步读取文件夹里面的所有文件
fs.readdir('./',(err,files)=>{
if (err) {
console.log(err);
} else{
// console.log(files); 返回的文件是个数组,可以用forEach循环输出文件名
files.forEach((x)=>{
console.log('有'+ x +'这个文件');
})
}
});
// 同步获取文件夹里面的所有文件
let files = fs.readdirSync('./public');
console.log(files); //返回的是一个数组
1.6删除文件
let fs = require('fs');

//异步操作删除1.text
fs.unlink('./1.text',(err)=>{
if (err) {
console.log(err);
} else{
console.log('删除文件成功');
}
}) //同步操作删除2.text
fs.unlinkSync('./2.text');
1.7删除文件目录
let fs = require('fs');

// 异步删除文件夹
fs.rmdir('../data/test1',function (error) {
if(error){
console.log('删除文件夹失败');
}else {
console.log('删除文件夹成功');
} }); // 同步方法
fs.rmdirSync('../data/test2');
1.8判断文件信息
let fs = require('fs');

// 异步获取文件的具体信息
fs.stat('../data/a.txt',(err,info)=>{
if (err) {
console.log('获取文件信息失败:',err);
} else{
// info.isFile() 判断是不是一个文件 返回结果为true
console.log(info.isFile());
// false
console.log(info.isDirectory());
}
});
// 同步操作获得文件信息并判断是不是文件夹
let file = fs.statSync('./1.text'); if(file.isFile()){
console.log('这是一个文件');
}else if(file.isDirectory()){
console.log('只是一个文件夹');
}else{
console.log('抱歉这不是一个文件或者文件夹');
}
1.9复制大文件
var fs = require('fs');
//创建读取流
var readStream = fs.createReadStream('./1.zip');
//创建写入流
var writeStream = fs.createWriteStream('./2.zip');
//进行大文件的复制
readStream.pipe(writeStream);
2.path模块的使用

path模块用来处理路径相关内容

2.1格式化路径
let path = require('path');
let url = path.normalize('d:\\\hd///arr/indexindex.php'); // d:\hd\arr\index\index.php
console.log(url);
2.2组合多个路径
let path = require('path');
let url = path.join('d:/www','/index','/banner/index.php');
// d:\www\index\banner\index.php
console.log(url);
2.3判断路径是否为绝对路径
const path = require('path');

let url = path.isAbsolute('c:/www/baidu/public/index');//绝对路径(true)
let url_ = path.isAbsolute('www/baidu/public/index');//相对路径(false) // true ,false
console.log(url,url_);
2.4解析并组合绝对路径
let path = require('path');

//从后往前组合,组合成第一个绝对路径就停止
//若直到要第一个参数都组合不出来绝对路径,那么就会连接上当前脚本所在结对路径,组合成一个完整的绝对路径
let url = path.resolve('c:/www','b:/res','index.php');
let url_ = path.resolve('../data/','a.txt'); // b:\res\index.php
console.log(url);
// F:\vue_project\learn_nodeJs\src\data\a.txt
console.log(url_);
2.5最后一个文件或者文件夹所在的路径
let path = require('path');
//dirname() 返回的是路径最后一个文件或者文件夹的所在路径
let url = path.dirname('F:\\vue_project\\learn_nodeJs\\src\\data\\a.txt');
// F:\vue_project\learn_nodeJs\src\data
console.log(url);
2.6最后的文件或目录名
let path = require('path');
// 返回最后一个文件名或者文件夹名
let url = path.basename('F:\\vue_project\\learn_nodeJs\\src\\data\\a.txt');
console.log(url);
2.7获取文件扩展名
let path = require('path');
// 返回最后一个文件名或者文件夹名
let url = path.extname('../data/a.txt');
console.log(url);
2.8获取当前分隔符
let path = require('path');
let separator = path.sep;
console.log(separator);
2.9删除指定文件目录下的文件和目录
let fs = require('fs');
let path = require('path'); let del = (url)=>{
//获得所有文件
let arr = fs.readdirSync(url);
//循环所有文件
arr.forEach((x)=>{
//组合文件路径
let fileurl = path.resolve(url,x);
//获得文件的详细信息
let xinxi = fs.statSync(fileurl);
// 判断
if(xinxi.isFile()){
fs.unlinkSync(fileurl);//是文件删除
}else if(xinxi.isDirectory()){
del(fileurl);//是文件夹递归调用
}
})
//删除文件夹(如果文件夹里面有文件删除不了)
fs.rmdirSync(url);
}
del(path.resolve(__dirname,'public.1'));
2.10获取指定目录下的文件信息
let fs = require('fs');
let path = require('path'); let del = (url,y=0)=>{ let h = '';
for (var i = 0; i < y; i++) {
h += '---'
}
//打印目录二级以后的目录
console.log(h + url); //获得所有文件
let arr = fs.readdirSync(url);
//循环所有文件
arr.forEach((x)=>{
//组合文件路径
let fileurl = path.resolve(url,x);
//获得文件的详细信息
let info = fs.statSync(fileurl);
let f ='';
for (let a=0;a<y+1;a++) {
f += '---';
}
//输出的文件为再次加 ---- 个,(看上班for循环 d+1 )
!info.isFile(fileurl) || console.log(f + fileurl);
!info.isDirectory(fileurl) || del(fileurl,y+1);
}) }
del(path.resolve(__dirname,'public.2'));
结果:
F:\前端学习\node\public.2
---F:\前端学习\node\public.2\06.js
---F:\前端学习\node\public.2\1.vue
---F:\前端学习\node\public.2\16.json
---F:\前端学习\node\public.2\16.vue
---F:\前端学习\node\public.2\ab
------F:\前端学习\node\public.2\ab\06.js
------F:\前端学习\node\public.2\ab\1.vue
------F:\前端学习\node\public.2\ab\16.json
------F:\前端学习\node\public.2\ab\16.vue
------F:\前端学习\node\public.2\ab\index.html
---F:\前端学习\node\public.2\index.html
3.Http模块的使用
3.1基本使用示例代码

示例一:基本的使用

// 1.引入网络相关模块
var http = require('http'); // 2.创建服务器
var server = http.createServer(); // 3.接受请求处理
server.on('request',function (request,response) {
console.log('收到来自此IP的请求:',request.remoteAddress);
console.log('请求URL:',request.url);
response.setHeader('Content-Type','text/plain;charset=utf-8');
response.write('已响应请求');
response.end();
}); // 4.绑定并监听此端口号
server.listen(3000,function () {
console.log('服务已启动');
});

示例二:根据路由返回不同内容


var http = require('http');
var fs = require('fs'); var server = http.createServer(); // 3.接受请求处理
server.on('request',function (request,response) { let url = request.url;
console.log(url); // 返回一张图片
if(url === '/image'){
fs.readFile('../data/b.jpg',function (error,data) {
if(error){
console.log('读取文件失败');
}else {
console.log('已读取文件');
response.setHeader('Content-Type','image/jpeg');
response.end(data);
}
});
} }); // 4.绑定并监听此端口号
server.listen(3000,function () {
console.log('服务已启动');
});

示例三:返回不同的Html模板

//引入http模块相当于php的apache (node.js不像php,http模块是node.js自带的)
let http = require('http');
let fs = require('fs'); //初始化server服务
var server = http.createServer(); //监听端口
server.listen(3000,()=>{
console.log('---server服务启动,端口3000---');
}) //监听用户请求
//req : 客户端请求的相关信息和方法
//res : 客户端相应的一些方法
server.on('request',(req,res)=>{
if(req.url == '/'){
// 读取首页模版
fs.readFile('./view/index.html',(err,data)=>{
if(err){
console.log(err);
}else{
res.end(data);
}
})
}else if(req.url == '/list'){
// 读取列表页模版
fs.readFile('./view/list.html',(err,data)=>{
if(err){
console.log(err);
}else{
res.end(data);
}
})
}else if(req.url == '/page'){
// 读取内容页面模版
fs.readFile('./view/page.html',(err,data)=>{
if(err){
console.log(err);
}else{
res.end(data);
}
})
}else{
res.end('<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>404页面没找到;</body></html>');
}
})
3.2模块化的路由封装
var http = require('http');
var url = require('url');
var router = require('./module/router.js'); http.createServer(function(req, res) {
if(req.url.indexOf('favicon') != -1){
res.end();
return false;
}
res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
var pathName=url.parse(req.url,true).pathname.replace('/','');
// 封装的路由函数
try {
router[pathName](req,res);
} catch(e) {
router['home'](req,res);
}
res.end();
}).listen(8001);
//router.js
var ejs = require('ejs');
var url = require('url'); var router={
home:function(req,res){
res.end('首页');
},
login:function(req,res){
ejs.renderFile('./views/login.html',{},function(err,data){
res.end(data);
})
},
dologin:function(req,res){
var info=url.parse(req.url,true);
info=JSON.parse(JSON.stringify(info));
ejs.renderFile('./views/dologin.html',{query:info.query},function(err,data){
res.end(data);
})
}
} module.exports=router;
4.url模块的使用

引入并打印Url模块,看看都有哪些方法

cosnt url = require('url');
console.log(url);

下面是有关方法的截图

查阅文档发现,以下api其实官方已经弃用了[url=http://nodejs.cn/api/url.html]

但是在这里还是要说一说它的用法

4.1url.parse()方法
cosnt url = require('url');

/*
* url.parse方法:
* urlStr:要解析成对象的url字符串
* parseQueryString:是否解析查询参数,默认为false
* slashesDenoteHost:是否以斜线解析主机名,默认为false
* */
let urlWithStringQuery = url.parse('http://localhost:8080/test?name=xiaoming&age=20');
console.log(urlWithStringQuery);

解析后的内容是个Url对象,可以通过其中的属性访问解析的值

Url {
protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:8080',
port: '8080',
hostname: 'localhost',
hash: null,
search: '?name=xiaoming&age=20',
// 如果方法的第二个参数为true,这里会解析成object
// query: [Object: null prototype] { name: 'xiaoming', age: '20' },
query: 'name=xiaoming&age=20',
pathname: '/test',
path: '/test?name=xiaoming&age=20',
href: 'http://localhost:8080/test?name=xiaoming&age=20'
}
4.2url.format()方法

format就是parse的返过程,把对象转换成url字符串

const url = require('url');

let urlObj =  {
protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:8080',
port: '8080',
hostname: 'localhost',
hash: null,
search: '?name=xiaoming&age=20',
query: 'name=xiaoming&age=20',
pathname: '/test',
path: '/test?name=xiaoming&age=20',
href: 'http://localhost:8080/test?name=xiaoming&age=20'
}; let parseUrl = url.format(urlObj); // 结果:http://localhost:8080/test?name=xiaoming&age=20
console.log(parseUrl);
4.3url.resolve()方法

用于解析Url路径,有以下用法

const url = require('url');
url.resolve('/one/two/three', 'four'); // '/one/two/four'
url.resolve('http://example.com/', '/one'); // 'http://example.com/one'
url.resolve('http://example.com/one', '/two'); // 'http://example.com/two'
4.4url.search方法

这个方法用于获取网址后面的查询参数,或者给网址后面添加查询参数

// 获取查询参数
const myURL = new URL('http://localhost:8080/test?name=xiaoming&age=20');
// 打印结果:
// ?name=xiaoming&age=20
console.log(myURL.search);
// 设置查询参数
const my_url = new URL('http://localhost:8080/test');
my_url.search = 'name=xiaoming&age=20';
// 结果:http://localhost:8080/test?name=xiaoming&age=20
console.log(my_url.href);
4.5 url.searchParams()方法

URLSearchParams接口和 querystring模块有相似的目的,但是 querystring 模块的目的更加通用,因为它可以定制分隔符(=)。 但另一方面,这个 API 是专门为 URL 查询字符串而设计的

这个方法来源于URLSearchParams类,但是可以通过url对象获取到,下面是这个方法的使用示例

const myURL = new URL('http://localhost:8080/test?name=xiaoming&age=20');
console.log(myURL.searchParams.get('name'));
console.log(myURL.searchParams.get('age'));

四、模块化与Node中的模块系统

1.什么是模块化
  • 模块化是一种bai将系统分离成du独立功能部zhi分的方法,可将dao系统分割成独立的功能部分zhuan,严格定义shu模块接口、模块间具有透明性。
  • 简单来说只要遵循一定的模块标准约束,就可以形成模块化,常见的js模块化标准有AMD和CommonJS
  • 模块化可以使得文件形成文件作用域,不同文件可以引入其他模块,各个模块解耦合,减少依赖。
2.commonJS规范
2.1有关概念

Node程序由许多个模块组成,每个模块就是一个文件。Node模块采用了CommonJS规范。

  • 根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在一个文件定义的变量(还包括函数和类),都是私有的,对其他文件是不可见的

  • CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

Node内部提供一个Module构建函数。所有模块都是Module的实例。每个模块内部,都有一个module对象,代表当前模块。它有以下属性。

属性 说明
id 模块的识别符,通常是带有绝对路径的模块文件名
filename 模块的文件名,带有绝对路径
loaded 返回一个布尔值,表示模块是否已经完成加载
parent 返回一个对象,表示调用该模块的模块
children 返回一个数组,表示该模块要用到的其他模块
exports 表示模块对外输出的值

下面是一个示例文件,最后一行输出module变量。

// example.js
var jquery = require('jquery');
exports.$ = jquery;
console.log(module);
{ id: '.',
exports: { '$': [Function] },
parent: null,
filename: '/path/to/example.js',
loaded: false,
children:
[ { id: '/path/to/node_modules/jquery/dist/jquery.js',
exports: [Function],
parent: [Circular],
filename: '/path/to/node_modules/jquery/dist/jquery.js',
loaded: true,
children: [],
paths: [Object] } ],
paths:
[ '/home/user/deleted/node_modules',
'/home/user/node_modules',
'/home/node_modules',
'/node_modules' ]
}
2.2导出成员变量
  • Node中是模块作用域,默认文件中所有的成员只在当前模块有效,对于希望可以被其他模块访问到的成员,我们需要把这些公开的成员都挂载到exports接口对象中就可以了

  • node为每一个模块提供了一个exports变量(可以说是一个对象),指向 module.exports。这相当于每个模块中都有一句这样的命令 var exports = module.exports;

这样,在对外输出时,可以在这个变量上添加方法。例如 exports.add = function {return Math.PI * r *r};注意:不能把exports直接指向一个值,这样就相当于切断了 exports 和module.exports 的关系。例如 exports=function(x){console.log(x)};

一个模块的对外接口,就是一个单一的值,不能使用exports输出,必须使用 module.exports输出。module.exports=function(x){console.log(x);};

总结来说:exports可以导出多个值,而modulex.exports只能导出单一的值。根据阮一峰的教程来说,两个不好区分,那就放弃 exports,只用 module.exports 就好。

例子:

使用exports导出多个值

exports.a = 123;
exports.b = function(){
console.log('bbb')
};
exports.c = {
foo:"bar"
};
exports.d = 'hello';

使用module.exports导出单一值

module.exports = 'hello';
// 只能导出单一值,后者会覆盖前者
module.exports = function add(x,y) {
return x+y;
}

不过,也有办法像exports一样导出多个值,那就是导出一个对象

// 也可以通过以下方法来导出多个成员
module.exports = {
foo = 'hello',
add:function(){
return x+y;
}
};
2.3加载导出的模块

使用require关键字即可

var example = require('./example.js');

模块加载规则:

根据模块的不同,会优先加载不同类型的模块

  • 如果模块已经存在缓存中,则会优先加载缓存中的模块
  • 如果是Node.js中的核心模块,则会先去加载核心模块
  • 如果是第三方库模块(node_modules),则会去加载第三方库模块
  • 最后才会加载我们手写的模块,一般这个是否都是路径形式的模块了

根据参数的不同格式,require命令去不同路径寻找模块文件。

  • 如果参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。比如,require(’/home/marco/foo.js’)将加载/home/marco/foo.js
  • 如果参数字符串以“./”开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件。比如,require(’./circle’)将加载当前脚本同一目录的circle.js
  • 如果参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)
  • 如果参数字符串不以“./“或”/“开头,而且是一个路径,比如require(‘example-module/path/to/file’),则将先找到example-module的位置,然后再以它为参数,找到后续路径
  • 如果指定的模块文件没有发现,Node会尝试为文件名添加.js、.json、.node后,再去搜索。.js件会以文本格式的JavaScript脚本文件解析,.json文件会以JSON格式的文本文件解析,.node文件会以编译后的二进制文件解析

模块的缓存:

  • 第一次加载该模块,node会缓存该模块。再次加载,直接从缓存中取出该模块的module.exports属性。

  • 删除模块的缓存 缓存保存在require.cache中,可操作该属性进行删除

    // 删除指定模块的缓存
    delete require.cache[moduleName];
    // 删除所有模块的缓存
    Object.keys(require.cache).forEach(function(key){
    delete require.cache[key];
    })

五、Node的其他配置

1.NPM

npm全称就是node package manage(node包管理器),用于下载各种第三方模块资源,例如通过npm命令安装jQuery包(npm install --save jquery),在安装时加上–save会主动生成说明书文件信息(将安装文件的信息添加到package.json里面)

NPM命令行工具:

  • npm是一个命令行工具,只要安装了node就已经安装了npm。

  • npm也有版本概念,可以通过npm --version来查看npm的版本

升级NPM(我升我自己)

npm install --global npm

常见的NPM命令

命令 说明
npm init 生成package.json描述说明文件
npm install 一次性把dependencies选项中的依赖项全部安装
npm install [packageName] 下载依赖包
npm install --save [packageName] 下载并且保存依赖项(package.json文件中的dependencies选项)
npm uninstall [packageName] 只删除,如果有依赖项会依然保存
npm uninstall --save [packageName] 删除的同时也会把依赖信息全部删除
npm help 查看使用帮助
npm cache clear 可以清空NPM本地缓存
npm ls 查看已安装的模块,-g 查看全局已安装的模块
npm config list 查看配置
2.package.json描述文件

每一个项目都要有一个package.json文件(包描述文件,就像产品的说明书一样)

这个文件可以通过npm init自动初始化出来

{
"name": "cls",
"version": "1.0.0",
"description": "这是一个测试项目",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "xiaochen",
"license": "ISC"
}

对于目前来讲,最有用的是dependencies选项,可以用来帮助我们保存第三方包的依赖信息。

如果node_modules删除了也不用担心,只需要在控制面板中npm install就会自动把package.json中的dependencies中所有的依赖项全部都下载回来。

  • 建议每个项目的根目录下都有一个package.json文件
  • 建议执行npm install 包名的时候都加上--save选项,目的是用来保存依赖信息(新版本无需加–save参数也会自动保存了)

除此,还有一个package-lock.json这个文件,出现于Npm5之后。当你安装包的时候,npm都会生成或者更新package-lock.json这个文件

  • npm5以后的版本安装都不要加--save参数,它会自动保存依赖信息

  • 你安装包的时候,会自动创建或者更新package-lock.json文件

  • package-lock.json这个文件会包含node_modules中所有包的信息(版本,下载地址…),这样的话重新npm install的时候速度就可以提升

  • package-lock.json的另外一个作用就是锁定版本号,防止自动升级

3.__dirname和__filename成员变量

在Node模块中,除了require,exports等模块成员变量之外,还有两个特殊的成员:

  • __dirname,是一个成员,可以用来动态获取当前文件模块所属目录的绝对路径
  • __filename,可以用来动态获取当前文件的绝对路径(包含文件名)
  • __dirnamefilename是不受执行node命令所属路径影响的

在文件操作中,使用相对路径是不可靠的,因为node中文件操作的路径被设计为相对于执行node命令所处的路径。所以为了解决这个问题,只需要把相对路径变为绝对路径(绝对路径不受任何影响)就可以了。就可以使用__dirname或者__filename来帮助我们解决这个问题

打印这两个变量的值

console.log('dirname:',__dirname);
console.log('filename:',__filename); // 输出结果
// dirname: F:\vue_project\learn_nodeJs\src\04-path模块的使用
// filename: F:\vue_project\learn_nodeJs\src\04-path模块的使用\09-filename和dirname成员变量.js

六、Express框架的使用

概念:

Express 是一个方便开发者的 web 框架,可以让开发者可以方便地处理路由,Cookie, 静态文件,上传文件, RESTFULL风格等等常见操作。

1.安装
npm install express --save
2.第一个实例入门
// 1.引入依赖
const express = require('express'); // 2.创建实例
const app = express(); // 3.监听get请求
app.get('/',(req,res)=>{
res.send('第一个入门实例');
}); app.get('/getData',(req,res)=>{
let obj = {
name: '小明',
age: '20'
};
// 这里返回的是格式数据
// send方法会自动设置返回数据类型,根据传入的数据类型不同
res.send(obj);
}); // 4.监听端口
app.listen(3000);
console.log('启动完成');
3.中间件(middleware)的使用

中间件(middleware)就是一个方法,这个方法可以用来处理http请求,但是一般情况下,中间件方法需要携带next参数。

它最大的特点就是,一个中间件处理完,再传递给下一个中间件,也就是说可以在下一次请求中访问上一次的数据

3.1使用中间件的例子:

每个中间件可以从App实例,接收三个参数,依次为request对象(代表HTTP请求)、response对象(代表HTTP回应),next回调函数(代表下一个中间件)。每个中间件都可以对HTTP请求(request对象)进行加工,并且决定是否调用next方法,将request对象再传给下一个中间件。

// use方法的使用类似all方法,都是能够接收任何请求,例如:get、post、put/delete…
// path表示请求的路径
// callback为回调函数,接收三个参数requset,response,next
// next回调函数必须被声明执行才能到达下一个中间件
app.use(path,callback);

下面是一个简单的示例:

const express = require('express');

const app = express();

// 默认路径是 "/"
app.use((req,res,next) => {
console.log('请求经过了中间件');
next();
}); app.get('/',(req,res,next) => {
console.log('访问了路径/');
res.send('访问了路径/');
}); app.get('/test',(req,res,next) => {
console.log('访问了路径/test');
res.send('访问了路径/test');
});

最后打印的结果是

服务启动完成...
请求经过了中间件
访问了路径/
请求经过了中间件
访问了路径/test

所以我们可以得出结论,无论是访问任何一个路径,都经过了没有声明访问路径中间件。

下面再看另外一个例子:

const express = require('express');

const app = express();

// 默认路径是 "/"
app.use((req,res,next) => {
console.log('请求经过了中间件');
next();
}); app.use('/request',(req,res,next) => {
console.log('请求经过了request中间件');
next();
}); app.use('/other',(req,res,next) => {
console.log('请求经过了other中间件');
next();
}); app.get('/',(req,res,next) => {
console.log('访问了路径/');
res.send('访问了路径/');
}); app.get('/test',(req,res,next) => {
console.log('访问了路径/test');
res.send('访问了路径/test');
}); app.get('/request',(req,res,next) => {
console.log('访问了路径/request');
res.send('访问了路径/request');
});

当浏览器地址输入http://localhost:3001/时,得到结果

请求经过了中间件
访问了路径/

当浏览器地址输入http://localhost:3001/test时,得到结果

请求经过了中间件
访问了路径/test

当浏览器地址输入http://localhost:3001/request时,得到结果

请求经过了中间件
请求经过了request中间件
访问了路径/request

由此我们又可以得出一个结论,当我们去访问某个路径时,会走没有声明path变量的中间件,也就是默认中间件,还会走声明了对应路径的中间件。

3.2利用中间件传递数据

下面是使用的一个例子

const express = require('express');

const app = express();

app.use('/getData',(req,res,next) => {
req.student = { name:'xiaoming',age:20 };
// 必须调用此方法以继续传递到下一个中间件
next();
}); app.get('/getData',(req,res) => {
console.log(req.student);
res.send(req.student);
}); app.listen(3000,function () {
console.log('服务已启动');
});
3.3一个简单的应用场景
//引入express框架
const express = require('express');
//创建网站服务器
const app = express();
//网站公告 在函数中没有使用next 所以代码走到这儿就不会往下走了 这就是网站维护时 公告的使用
app.use((req, res, next) => {
res.send('<h1>当前网站正在维护...</h1>')
});
//查询登录状态
//如果登录了的话 就使用next继续往下执行 否则输出信息 不继续往下执行
app.use('/admin', (req, res, next) => {
// 业务操作...
// 设置登录状态
let isLogin = true;
//如果用户登录 让请求继续向下执行
if (isLogin) {
next();
} else {
//如果用户没有登录 直接对客户端做出响应
res.send('您还没有登录 不能访问/admin这个页面')
}
})
app.get('/admin', (req, res) => {
res.send('您已经登录 可以访问当前页面')
})
//自定义404页面
app.use((req, res, next) => {
//为客户端响应404状态码已经提示信息
res.status(404).send('当前访问的页面不存在404') })
app.listen(3000);
console.log("网站服务器启动成功");
3.3错误处理

利用状态码进行错误处理

const express = require('express');
const fs = require('fs'); const app = express(); app.get('/readFile',(req,res,next) => {
fs.readFile('../data/xx.txt',((err, data) => {
if(err){
next(err);
}else {
res.send(data.toString(),);
}
}));
}); app.use(function (error,req,res,next) {
console.log(error);
res.status(500).send(error.message);
}); app.listen(3000,function () {
console.log('服务已启动');
}); // 给个不存在的路径,结果就会输出:no such file or directory

或者利用try catch处理

const express = require('express');
// 不引入这个模块就会报错
// const fs = require('fs'); const app = express(); app.get('/readFile',(req,res,next) => {
try {
fs.readFile('../data/xx.txt', ((err, data) => {
if (err) {
next(err);
} else {
res.send(data.toString(),);
}
}));
} catch (e) {
// 传递这个错误对象
next(e);
}
}); app.use(function (error,req,res,next) {
console.log(error);
res.status(500).send(error.message);
}); app.listen(3000,function () {
console.log('服务已启动');
}); // 最后输出: fs is not defined
3.4获取get参数
const express = require('express');

const app = express();

app.get('/getStudentById',(req,res) => {
// 获取到的结果是个对象类型:{ id: '1' }
console.log(req.query);
if(req?.query?.id){
if(req.query.id === '20'){
res.send({name:'小明',age:18,id:20})
}else {
res.send('未找到对应学生');
}
}else {
res.send("<h3>缺乏必要参数!</h3>");
}
}); app.listen(3000,function () {
console.log('服务已启动');
});
3.5获取post参数

先安装body-parser模块,用于解析参数

npm install --save body-parser

代码示例,用PostMan发送x-www-form-urlencoded格式数据即可

const express = require('express');
const bodyParser = require('body-parser'); const app = express(); // 利用中间件拦截请求
// extended:true使用第三方模块qs处理,false使用公共模块queryString进行处理
app.use(bodyParser.urlencoded({extended:false})); app.post('/addStudent',(req,res) => {
console.log(req.body);
const s = JSON.stringify(req.body);
res.send('添加成功:'+s);
}); app.listen(3000,function () {
console.log('服务已启动');
});

页面显示结果

{"name":"小明","age":18,"id":20}
3.6路径参数
const express = require('express');

const app = express();

app.get('/index/:id/:name',(req,res)=>{
res.send(req.params);
}); app.listen(3000,function () {
console.log('服务已启动');
});
// 访问http://localhost:3000/index/1/xiaoming
// 网页显示结果:{"id":"1","name":"xiaoming"}

当然你还可以指定哪些参数不必传,但是至少得传递一个参数,并且传递一个参数时总会给路径最后一个参数赋值

app.get('/index?/:id?/:name',(req,res)=>{
res.send(req.params);
}); // 例如:访问http://localhost:3000/index/xiaoming
// 结果:{"name":"xiaoming"}
3.7访问静态资源

使用express提供的static方法就好

const express = require('express');
const app = express(); // 访问静态资源
console.log(__dirname);
app.use('/data',express.static('../data/')); app.listen(3000,function () {
console.log('服务已启动');
});

NodeJS入门学习教程的更多相关文章

  1. MyBatis入门学习教程-使用MyBatis对表执行CRUD操作

    上一篇MyBatis学习总结(一)--MyBatis快速入门中我们讲了如何使用Mybatis查询users表中的数据,算是对MyBatis有一个初步的入门了,今天讲解一下如何使用MyBatis对use ...

  2. Linux入门学习教程:虚拟机体验之KVM篇

    本文中可以学习到的命令: 1. aptitude 是apt-get 不会产生垃圾的版本 2.       dpkg -L virtualbox 显示属于该包的文件 lsmod | grep kvmfi ...

  3. Nginx 入门学习教程

    昨天听一个前同事说他们公司老大让他去研究下关于Nginx 方面的知识,我想了下Nginx 在如今的开发技术栈中应该会很大可能会用到,所以写篇博文记录总结下官网学习教程吧. 1. 什么是Nginx? 我 ...

  4. PHP 入门学习教程及进阶(源于知乎网友的智慧)

    思过崖历程: 自学的动机.自学的技巧.自学的目标三个方面描述学习PHP的经历 一.自学的动机: 一定要有浓厚的兴趣,兴趣是最后的老师,可以在你迷茫的时候不断地支撑着你走下去. 自学不是为了工作,不是为 ...

  5. gulp入门学习教程(入门学习记录)

    前言 最近在通过教学视频学习angularjs,其中有gulp的教学部分,对其的介绍为可以对文件进行合并,压缩,格式化,监听,测试,检查等操作时,看到前三种功能我的心理思想是,网上有很多在线压缩,在线 ...

  6. Julia 入门学习教程

    有一门语言,它看起来像 Python ,感觉起来像 Lisp ,运行起来又像 C 一样快速,他就是Julia. 近年来,Julia 语言已然成为编程界的新宠,尤其在科学计算和人工智能领域炙手可热. 据 ...

  7. NodeJs入门学习(一)

    NodeJs是针对前端工程师向web后端深入理解的一门很好的语言. 首先,记录NodeJS几大特性,后续补充: 一.Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. ...

  8. 屌丝逆袭--Asp.net快速入门学习教程 第1晚

    本人屌丝一名,因工作原因,不能白天学习编程,所以只能做夜猫子学习编程,期待一天能逆袭成一名高帅富的技术大牛(靠,都想到流口水了........囧). 本教程记录本屌丝学习Asp.net的过程,大牛就飞 ...

  9. Python入门学习教程:数据库操作,连接MySql数据库

    各位志同道合的同仁可以点击上方关注↑↑↑↑↑↑ 本教程致力于程序员快速掌握Python语言编程. 本文章内容是基于上次课程Python教程:Python教程:连接数据库,对数据进行增删改查操作 和py ...

随机推荐

  1. h5问题总结

    一.下拉刷新上拉加载 主要依赖一款插件mescroll.js  http://www.mescroll.com/ 简单好用.以前同事的用法是初始化执行执行上拉会调,页数从0开始,下拉重新加载当前地址走 ...

  2. 简单4步,利用Prometheus Operator实现自定义指标监控

    本文来自Rancher Labs 在过去的文章中,我们花了相当大的篇幅来聊关于监控的话题.这是因为当你正在管理Kubernetes集群时,一切都会以极快的速度发生变化.因此有一个工具来监控集群的健康状 ...

  3. lock与synchronized 的区别【网上收集】

    1. 区别 类别 synchronized Lock 存在层次 Java的关键字,在jvm层面上 是一个接口 锁的释放 1.以获取锁的线程执行完同步代码,释放锁 2.线程执行发生异常,jvm会让线程释 ...

  4. 一行 CSS 代码的魅力

    之前在知乎看到一个很有意思的讨论 一行代码可以做什么? 那么,一行 CSS 代码又能不能搞点事情呢? CSS Battle 首先,这让我想到了,年初的时候沉迷的一个网站 CSS Battle .这个网 ...

  5. Pytest测试框架(五):pytest + allure生成测试报告

    Allure 是一款轻量级.支持多语言的开源自动化测试报告生成框架,由Java语言开发,可以集成到 Jenkins. pytest 测试框架支持Allure 报告生成. pytest也可以生成juni ...

  6. cornerstoneTools 作用,用法,api使用心得

    一.cornerstoneTools的用途 1.作用可以响应一些事件,例如鼠标按下的事件,鼠标滚轮的事件或按键或触摸事件 2.可以对视口进行缩放平移 3.可以在图像上绘制图形 4.可以在图像上绘制文本 ...

  7. linux mysql source 导入大文件报错解决办法

    找到mysql的配置文件目录 my.cnf interactive_timeout = 120wait_timeout = 120max_allowed_packet = 500M 在导入过程中可能会 ...

  8. 【Linux】kali 安装 python3 和 pip3(亲测有效)

    [Linux]kali 安装 python3 和 pip3 引言:   在使用kali的时候,经常会用到各种工具以及脚本,而大多数脚本都是以python编写的,但是烦就烦在python有2个版本,有些 ...

  9. Centos 安装 Node-v12.17.0-linux-x64.tar.gz

    wget https://nodejs.org/dist/v12.17.0/node-v12.17.0-linux-x64.tar.gz tar -zxf node-v12.17.0-linux-x6 ...

  10. Centos 7 下的KVM虚拟机

    一 什么是KVM虚拟机: KVM虚拟机 Kernel-based Virtual Machine的简称,是一个开源的系统虚拟化模块,自Linux 2.6.20之后集成在Linux的各个主要发行版本中. ...