Node.js
服务端开发要做的事情:实现网站的业务逻辑,数据的增删改查。
Node是一个基于Chrome V8引擎的JS代码运行环境。
Node.js组成:ECMAScript和Node模块Api.
Node全局对象global.
Node中全局对象有以下方法,可以在任何地方使用,global可以省略。
console.log() 在控制台中输出
setTimeout() 设置超时定时器
clearTimeout() 清除超时定时器
setInterval() 设置间歇定时器
clearInterval() 清除间歇定时器
Node.js规定一个js文件就是一个模块,模块内部定义的变量,和函数默认情况下在外部无法得到。
模块内部可以使用exports对象进行成员导出,使用require方法导入其他模块。
模块成员导出
//a.js
let version = 1.0;
const sayHi = name => `您好,${name}`;
exports.version = version;
exports.sayHi = sayHi;
模块成员导入
//b.js
let a = require('./b.js');
console.log(a.version);
console.log(a.sayHi('黑马讲师');
导入模块时后缀可以省略。
模块成员导出的另一种方式
module.exports.version=version;
module.sayHi=sayHi;
exports 是 module.exports的别名(地址引用关系),导出对象最终以module.exports为准。
系统模块
1.文件模块-读取文件、写入文件、创建文件夹
系统模块fs文件操作
const fs =require('fs');
读取文件内容
fs.reaFile('文件路径/文件名称',['文件编码'],callback);
写入文件
fs.writeFile('文件路径/文件名称','数据',callback);
const content = `<h3>正在使用fs.writeFile写入文件内容</h3>';
fs.writeFile('../index.html',content,err => {
if (err != null) {
console.log(err);
return;
}
console.log('文件写入成功');
});
2.系统模块path 路径操作
为什么要进行路径操作-
不同操作系统的路径分隔符不统一
/public/upload/avatar
Window上是\ /
Linux上是/
路径拼接语法
path.join('路径','路径',...)
导入path模块
const path = require('path');
路径拼接
let finialPath = path.join('itcast','a','b','c.css');
输出结果itcast/a/b/c.css
console.log(finialPath);
相对路径vs绝对路径
大多数情况下使用绝对路径,因为相对路径有时候相对的是命令行工具的当前工作目录,在读取文件或者设置文件路径时都会选择绝对路径,使用_dirname获取当前文件所在的绝对路径。
第三方模块
获取第三方模块
npm: node的第三方模块管理工具
下载:npm install 模块名
卸载:npm uninstall package 模块名称
全局安装与本地安装
命令行工具:全局安装
库文件:本地安装
第三方模块nodemon 是一个命令行工具,用以辅助项目开发,自动刷新。
使用步骤:使用npm install nodemon -g 下载它
在命令行工具中用nodemon命令替代node命令执行文件。
第三方模块nrm:npm下载地址切换工具
npm默认的下载地址在国外,国内下载速度慢
使用步骤:
使用npm install nrm -g下载它
查询可用的下载地址列表 nrm ls
切换npm下载地址nrm use 下载地址名称
第三方模块Gulp
基于node平台开发的前端构建工具,将机械操作编写成任务,想要执行机械化操作时执行一个命令行命令任务就能自动执行了,用机械代替手工,提高开发效率。
Gulp能做什么:
项目上线,HTML,css,js文件压缩合并,语法转换(es6,less...),公共文件抽离,修改文件浏览器自动刷新。
Gulp使用:
使用npm install gulp下载gulp库文件,
在项目根目录下建立gulpfile.js文件,
重构项目的文件夹结构src目录放置源代码文件dist目录放置构建后文件,
在gulpfile.js文件中编写任务,
在命令行工具中执行gulp任务。
Gulp提供的方法:
gulp.src() 获取任务要处理的文件
gulp.dest() 输出文件
gulp.task() 建立gulp任务
gulp.watch() 监控文件的变化
const gulp = require('gulp');
//使用gulp.task()方法建立任务
gulp.task('first', () => {
//获取要处理的文件
gulp.src('./src/css/base.css');
//将处理后的文件输出到dist目录
.pipe(gulp.dest(./dist/css));
});
Gulp插件
gulp-htmlmin:html文件压缩
gulp-csso :压缩css
gulp-babel :js语法转换
gulp-less:less语法转换
gulp-uglify : 压缩混淆js
gulp-file-include : 公共文件包含
browsersync浏览器实时同步
package.json文件
node_modules 文件夹的问题-记录模块依赖关系。
package.json文件的作用-项目描述文件,记录当前项目信息,
使用npm init -y命令生成。
项目依赖-dependencies字段
开发依赖-devDependencies
package-lock.json文件的作用
锁定包的版本,确保再次下载时不会因为版本不同而产生问题。
模块查找规则-当模块拥有路径但没有后缀时
require('./find.js');
require('./find');
require方法根据模块路径查找模块,如果是完整路径,直接引入模块。
如果模块后缀省略先找同名JS文件再找同名JS文件夹。
如果找到了同名文件夹,找到文件夹中的index.js。
如果文件夹中没有index.js,就会去当前文件夹中的package.json文件中查找main选项中的入口文件。
如果找指定的入口文件不存在或者没有指定入口文件就会报错,模块没有被找到。
require('find');
Node.js会假设它是系统模块。
Node.js会去node_modules文件夹中。
首先看是否有该名字的JS文件。
再看是否有该名字的文件夹。
如果是文件夹看里面是否有index.js。
如果没有index.js查看该文件夹中的package.json中的main选项确定模块入口文件。
否则找不到报错。
【请求相应原理及HTTP协议】
1.服务器端基础概念
网站的组成-客户端和服务器端。
Node网站服务器
Ip地址
域名-网址
端口-计算机与外界通讯交流的出口,用来区分服务器电脑中提供的不同的服务。
URL-统一资源定位符,组成
传输协议://服务器ip或域名:端口/资源所在的位置标识
http://www.itcast.cn/news/20181018/09152238514.html
http超文本传输协议,提供了一中的发布和接受html页面方法。
本机域名localhost
本机ip: 127.0.0.1
2.创建web服务器
//引用系统模块
const http = require('http');
//创建web服务器
const app = http.createServer();
//当客户端发送请求的时候
app.on('request', (req,res) => {
//响应
red.end('<h1>hi,user</h>');
});
//监听3000端口
app.listen(3000);
console.log('服务器已启动,监听3000端口,请访问localhost:3000');
3.HTTP协议
http协议概念:
超文本传输协议,规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器框架工作,是客户端和服务器端请求和应答的标准。
报文:在http请求和响应的过程中传递的数据块就叫报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式。
请求报文
请求方式:GET 请求数据 POST 发送数据
请求地址:
app.on('request',(req,res) => {
req.headers //获取请求报文
req.url //获取请求地址
req.method //获取请求方法
});
响应报文
Http状态码
200请求成功
404请求的资源没有被找到
500服务器端错误
400客户端请求有语法错误
内容类型
text/html
text/css
application/javascript
image/jpeg
application/json
app.on('request', (req,res) =>{
//设置响应报文
red.writeHead(200, {
'Contwnt-Type': 'text/html;charset=utf8'
});
});
请求参数
GET请求参数
参数放置在浏览器地址栏中,例如http://localhost:3000/?name=li&age=18
参数获取需要借助系统模块url, url模块用来处理url地址。
const http = require('http');
//导入url系统模块,用于处理url地址
const url = require('url');
const app = http.createServer();
app.on('request', (req,res) => {
//将url路径的各个部分解析出来并返回对象
//true 代表将参数解析为对象格式
let {query} = url.parse(req.url,true);
console.log(query);
});
app.listen(3000);
POST请求参数
参数被被放置在请求体中进行传输
获取POST参数需要使用data事件和end事件
使用querystring系统模块将参数转换为对象格式
const http = require('http');
//导入url系统模块,用于处理url地址
const url = require('url');
const app = http.createServer();
app.on('request', (req,res) => {
//将url路径的各个部分解析出来并返回对象
//true 代表将参数解析为对象格式
let {query} = url.parse(req.url,true);
console.log(query);
});
//导入系统模块querystring用于将HTTP参数转换为对象格式
const querystring = require('querystring');
app.on('request', (req,res) => {
let postData = '';
//监听参数传输事件
req.on('data',(chunk) => postData += chunk;);
//监听参数传输完毕事件
req.on('end', () => {
console.log(querystring.parse(postData);
});
});
路由
http://localhost:3000/index
http://localhost:3000/login
路由是指客户端请求地址与服务器端程序代码的对应关系,简单来说,就是请求什么响应什么。
GET/index -路由- 响应首页
GET/list -路由- 响应列表页
GET/login -路由- 登录逻辑处理
//当客户端发来请求的时候
app.on('request',(req,res) => {
//获取客户端的请求路径
let {pathname} =url.parse(req.url);
if(pathname == '/' || pathname == '/index') {
res.end('欢迎来到首页');
} else if ( pathname == '/list') {
res.end('欢迎来到列表页');
} else {
red.end('抱歉,您访问的页面出游了');
}
});
静态资源
服务端不需要处理,可以直接响应给客户端的资源就是静态资源,例如CSS,JavaScript,image文件。
http://www.itcast.cn/image/logo.png
动态资源
相同的请求地址不同的响应资源,这种资源就是动态资源。
http://www.itcast.cn/article?id=1
http://www.itcast.cn/article?id=2
客户端请求途径
GET方式
浏览器地址栏
link标签的href属性
script标签的src属性
img标签的src属性
Form表单提交
POST方式
Form表单提交
Node.js异步编程
同步API,异步API
//拼接路径
const public = path.join(__dirname,'public');
//请求地址解析
const urlObj = url.parse(req.url);
//读取文件
fs.readFile('./demo.txt','utf8', (err,result) => {
console.log(result);
});
同步api:只有当前api执行完成后,才能继续执行下一个api
console.log('before');
console.log('after');
异步api:当前api执行不会阻塞后续代码的执行。
console.log('before');
setTimeout (
() => { console.log('last');
},2000);
console.log('after');
同步api和异步api的区别(获取返回值)
同步api可以从返回值中拿到api执行的结果,但是异步api是不可以的。
//同步
function sum (n1,n2) {
return n1+ n2;
}
const result = sum(10,20);
//异步
function getMsg () {
setTimeout(function ()
return { msg : 'Hello node.js'}
},2000);
}
const msg = getMsg();
回调函数
自己定义函数让别人调用
//getData函数定义
function getData (callback) {}
//getData函数调用
getData( () => {});
使用回调函数获取异步API执行结果
function getMsg (callback) {
setTimeout(function () {
callback ( {msg : 'Hello node.js'})
},2000);
}
getMsg ( function (msg) {
console.log(msg);
});
同步Api,异步Api的区别(代码执行顺序)
同步api从上到下依次执行,前面代码会阻塞后面代码的执行。
for(var i=0; i<100000; i++) {
console.log(i);
}
console.log('for循环后面的代码');
异步Api不会等待api执行完成后再向下执行代码。
代码执行顺序分析
Node.js中的异步Api
fs.readFile('./demo.txt', (err,result) => {});
ver server = http.createServer ();
server.on('request', (req,res) => {});
如果异步Api后面代码的执行结果,但实际上后续代码在执行的时候异步Api还没有返回结果,这个问题要怎么解决?
fs.readFile('./demo.txt', (err,result) => {});
console.log('文件读取结果');
Promise
出现的目的是解决Node.js异步编程中回调地狱的问题。
let promise = new Promise (resolve, reject) => {
setTimeout ( ()=> {
if (true) {
resolve({name : '张三'})
} else {
reject('失败了')
}
},2000);
});
promise.then(result => console.log(result);
.catch(err => console.log(error);
异步函数
异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。
const fn = async () => {};
async function fn () {}
async 关键字
普通函数定义前加async关键字,普通函数变成异步函数。
异步函数默认返回promise 对象。
在异步函数内部使用return 关键字进行结果返回,结果会包裹在promise对象中,return 关键字代替了resolve 方法。
在异步函数内部使用throw关键字抛出程序异常。
调用异步函数再链式调用then方法获取异步函数执行结果。
调用异步函数再链式调用catch方法获取异步函数执行的错误信息。
await关键字只能出现在异步函数中。
await promise await 后面只能写promise 对象,写其他类型的api是不可以的。
await关键字可是暂停异步函数向下执行,直到promise返回结果。