文章目录
前言
简单的说 Node.js 就是运行在服务端的 JavaScript。
Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
1 node是做什么的?
node属于后端,用来创建高性能的web服务器。
优点:1)处理高并发 2)处理IO密集比较有优势 input output
IO密集:操作文件,网络操作,数据库...
CPU密集:运算,压缩,解压,加密,解密....
--------------------------------------------------
客户端:
浏览器,手机上的软件,电脑上的软件,小程序,公众号,平板的软件,智能设备...
服务器:
本质也是一个计算机,它上面的软件和我们平常用的软件不一样,tomcat,mysql
--------------------------------------------------
web项目,主要就是接收用户请求,读取数据库中的数据,结合页面,把页面返回给客户端,所以使用node做web项目还是比较合适的。
node创建高性能web服务器:
说白了就是缩短请求和响应时间:
1)请求:客户端 我们控制不了 取决于网络
2)响应:响应快一点
提高服务器的带宽 cnd加速…
服务器处理快一点 程序员可以控制
读写数据库也需要快一点 程序员也可以控制 数据库的读写也是有瓶颈的…
客户端访问服务器:
通过一个url去访问服务器。
java为例:
多线程的 一个请求就会开一个线程,这个线程来处理这个请求 资源:CPU和内存
Node是单线程的:
让一个服务员拼命的干活。
什么是V8?
V8引擎是一款专门解释和执行JS代码的虚拟机, 任何程序只要集成了V8引擎都可以执行JS代码
例如:
1)将V8引擎嵌入到浏览器中,那么我们写的JavaScript代码就会被浏览器所执行
2)将V8引擎嵌入到NodeJS中,那么我们写的JavaScript代码就会被NodeJS所执行
2 node的使用
node是一个JS的运行环境,浏览器也是JS的运行环境。 如果JS运行在浏览器中,那么JS是运行在前端的,如果JS运行在NODE中,JS是运行在后端的。
node环境中,只能写ES代码,不能写DOM和BOM。
node中,把文件分成三种模块:
1)系统模块,也叫核心模块,是Node帮我们提供好的,我们直接用
加载模块,提供了一个方法,叫require()
载入http模块:require("http")
2)第三方模块,是一些大神写好的模块,我们也是直接用
3)自定义模块,我们自己写的模块
http模块:
此模块可以创建一台服务器。
端口:一个服务器上,可以提N个服务器,如何区分是哪一个服务器,就靠端口。
一共的端口数据:0~65535。0~1024不要用,知名端口也中用。暂时,你可以使用3000 5000
监听客户端的请求:
let http = require("http"); // 引入一个核心模块http
let server = http.createServer(); // 创建一台服务器
server.on("request",(req,res)=>{ // 注册一个请求事件
res.writeHead(200,{"content-type":"text/html; charset=utf-8"}); // 解决乱码 不需要记
res.write("hello 客户端"); // 给客户端响应数据
res.end(); // 结束响应
});
server.listen(3030,()=>{ // 监听一个端口,只要是一个服务,就要监听一个端口
console.log("3030服务成功了")
})
运行一个服务器:
1)鼠标右键 ----> run
2)定位代码的目录下面 ----> node xxx.js 不想运行此服务器,按两个ctrl(不要松)+ c(两次)
www.baidu.com ====> http://www.baidu.com
baidu.com 叫域名 39.156.66.18 叫IP名 域名相比IP好记
url:
http://127.0.0.1:3030
http://localhost:3030/news
http:// 协议 客户端与服务器之间通信的规则 汉语
127.0.0.1 每一台服务器都有一个IP地址 本地电脑如果充当服务器 那么此台电脑的IP地址是127.0.0.1
localhost 127.0.0.1对应的域名是localhost 是一个特殊的域名 每个人的电脑都一样
3030 端口 表示你访问服务器上的哪一个服务 通常我们访问网站,不需要加端口,原因是80端口是默认的
/news 路径 在端口后面放路径
3 npm使用
3.1 包(package)
包是由多个模块组合的(在node中每个js都是一个模块)
package.json:
记录安装的第三方模块(传项目时可通过npm i
恢复node_modules
中的模块)。
package-lock.json:
记录并锁死下载的第三方模块版本号。
包的相关概念:
1. 初始化包的信息文件: npm init -y 安装包之前,都是初始化包的信息。
2. 包分为全局包和本地包,代码中使用的都是本地包,全局包只能在命令行中使用。
3. npm之所以能够直接使用因为npm 放到了path目录,其他安装的全局包都在npm 下。所以可以直接当成全局命令来执行。
包描述文件package.json
, 定义了当前项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。
npm install
命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。
生成的配置文件package.json
如下:
{
"name": "nodeCode", // 项目的名字
"version": "1.0.0", // 项目的版本
"description": "", // 项目的描述
"main": "01-hello node.js", // 项目的入口
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1" // 配置一些命令
},
"keywords": [], // 项目的关键字
"author": "", // 项目的作者
"license": "ISC" // 项目遵循的协议
"dependencies": {/-------------------------项目依赖/
"jquery": "^3.6.0",
"react": "^17.0.2",
"vue": "^2.6.14"
},
"devDependencies": {/-----------------------开发依赖/
"less-loader": "^10.0.0",
"webpack": "^5.40.0"
}
}
注意点:package.json
文件中,不能
加入任何注释
1)dependencies:
生产环境包的依赖,一个关联数组,由包的名称和版本号组成。
2)devDependencies:
开发环境包的依赖,一个关联数组,由包的名称和版本号组成。
安装包:
包(依赖)的类型:
1) 开发依赖devDependencies(webpack)。
在项目开发的过程中需要的依赖,但是项目上线时,不需要了,叫开发依赖。
如:less 把less转成css的依赖 项目时,就不需要了。
安装:npm install webpack -D -D表示安装的依赖是开发依赖。
2) 项目依赖dependencies(vue) npm install vue -S 新版本可以省略。
项目上线时,还需要的依赖,没有这个依赖,项目就运行不了,叫项目依赖。
安装:npm install vue -S -S表示安装的是项目依赖。
3) 同版本依赖peerDependencies。
4) 捆绑依赖bundledDependencies npm pack打包时,可以把有些依赖打包进去。
5) 可选依赖optionalDependencies。
安装项目依赖:npm i xx -S
或npm i xx --save
(-s可省略不写)
安装开发依赖:npm i xx -D
或 npm i xx --save-dev
注意点:
-
将项目拷贝给其它人, 或者发布的时候, 我们不会将node_modules也给别人, 因为太大。
-
因为有的包可能只在开发阶段需要, 但是在上线阶段不需要, 所以需要分开指定。
npm i
所有的包都会被安装。
npm i --production
只会安装dependencies
/项目依赖中的包
npm i --development
只会安装devDependencies
/开发依赖中的包。
3.2 npm常用命令(包含node服务器启动命令)
下载第三方模块:
当我们安装了node,默认它就给我们安装了一个下载器,叫npm(node package manage)。
npm
表示下载器,默认
是去国外的npm网站上下载第三方模块,
npm -v
检测是否安装npm成功,成功则显示版本号。
npm install xxx
安装xxx第三方模块 默认就去国外下载源找。
install可以简写为i。
nrm是切源工具
,也可以查看源
。
nrm use taobao
切源为淘宝源
nrm ls
查看源
一般使用node需要以下几个第三方模块:
npm init -y
生成package.json
文件记录用了什么第三方模块
npm i express
安装使用express
第三方模块(可以快速创建一个服务器)
npm i ejs
引入ejs模板引擎
:循环遍历数据显示,实现数据与视图分离(即html结构与数据分离)ejs开发时需要,建立项目时也需要。
npm i -g nrm
全局安装,表示要安装一个工具,安装完这个工具,就可以在DOC窗口中使用这个工具。
node xx.js
启动服务器,但一般用下面的方式启动。
如果你修改了服务器代码,你需要重新启动服务器:先关闭服务器,再开启服务器。
npm i nodemon -g
全局安装nodemon工具可以自动重启服务器(安装一次就够了)。
nodemon xx.js
使用方式。需要在此js文件的当前目录启动服务。
4 web前置内容
4.1 交互
计算机之间的信息交流称之为:交互。
C/S
交互模型(架构)和B/S
交互模型(架构)
Client/Server
客户端/服务器:访问服务器资源必须安装客户端软件。
Browser/Server
浏览器/服务器:可以直接通过浏览器访问服务器资源。
二者各有优缺点…
4.2 Web服务器作用
数据库服务器:如果一个电脑上安装了mysql,此电脑就是一个数据库服务器。数据库服务器是提供数据服务的。
web服务器:作用是对外提供网站/网页服务的,如果一个电脑上安装了tomcat,那么这个电脑就是一个web服务器。
服务器: 提供数据服务的,本质是一台电脑,安装了不同的软件,对外提供不同的服务器。
客户端: 用户就可以通过浏览器访问这些资源(消费服务的)。
4.3 资源的分类(动/静态)
资源:计算机中数据文件。
- 静态资源
对于同一个页面,不同用户看到的内容是一样的(该资源不会变化)。
例如:体育新闻、网站门户等,常见后缀:*.html
、*.js
、*.css
, 图片,视频… - 动态资源
用对于同一个页面,不同用户看到的内容可能不一样(该资源会变化)。
例如:购物车、我的订单等,常见后缀:*.jsp
、*.aspx
、*.php
网络通信三要素:ip,端口,协议。
5 Node创建web服务器
在node中,没有所谓的web容器,node中的web容器(服务器)需要我们写代码去创建。
5.1 创建第一个web服务器
const http =require("http")
// 在服务器中写代码后,需要重启服务器,不方便,可以使用nodemon
// node需要写代码创建web服务器
// req是request的简写,表示请求对象,包含了很多的请求数据url mrthod
// res是response的简写,响应数据
let server=http.createServer((req,res)=>{
res.write("<h1>hello client~</h1>")
// 结束响应
res.end()
})
//server.on("request",(req,res)=>{//请求过来了,触发监听器
server.on("request",()=>{//请求过来了,触发监听器
console.log("请求进来了!!!");
})
server.listen(3000,()=>{//监听端口
console.log("服务器已经在3000端口开始运行了~");
})
5.2 Http协议概述
上网的本质:
- 客户端请求服务器,服务器给出响应式,不是一次请求和一次响应,是N次请求和N次响应。
- 先有请求,后有响应。 请求,我们叫HTTP请求,响应我们叫HTTP响应。
超文本传输协议(Hyper Text Transfer Protocol
)是互联网上应用最为广泛的一种网络协议。
html : Hyper Text Markup language
超文本标记语言 ( w3c : 万维网联盟)。
传输协议:在客户端和服务器端通信时,规范了传输数据的格式和内容
。
协议:http://
IP地址(域名):localhost
端口:8080
请求路径(请求资源):/index.html
请求参数(查询字符串):?name='wc'&age=100 此数据就是传输给服务器的数据
http协议的特点:
0) tcp/ip协议族: 链路层,网络层, 传输层(tcp), 应用层(http)
1) 基于tcp协议 : 传输层协议, 三次握手,保障数据安全,相对udp效率低
2) 默认端口 80 (省略不写)
完整版: http://localhost:80/a.html
省略版: http://localhost/a.html
https 的默认端口是443 (secure 安全, 对传输数据进行加密)
3) 基于请求/响应模型
一次请求对应一次响应 / 先有请求,再有响应
4). 无状态协议(多次请求之间相互独立,不记录状态)
http协议版本发展:
1). http1.0 (1996) : 每次请求都有一个新的连接(开销大,比较慢)
2). http1.1 (1999) : 长连接,多个请求共用一个连接(开销小一些,比较快)
传输的数据都是文本(比较慢), 不支持推送
目前!!!
3). http2.0 (2015) : 传输的数据经过压缩的,效率很高, 支持推送
http协议的内容:
1). 请求报文: 浏览器发送给服务器的数据。
请求行
,请求头
,请求体
2). 响应报文: 服务器发送给浏览器的数据。
响应行
,响应头
,响应体
抓包工具 (抓取基于http协议传输的数据包)
1. 在浏览器和服务器交互的时候(发送请求,然后响应),我们可以使用工具抓取数据查看
2. google浏览器内置开发者工具
5.3 http请求
浏览器
发出请求
传递数据到服务器
。
服务器
接收数据后响应
数据到浏览器
。
当请求服务器时,可以给服务器传递数据。
上网的本质:数据在客户端和服务器之间传输。
请求方式区别:get、post
get(请求行、请求头)
1.请求参数在地址栏显示(请求行)
2.请求参数大小有限制
3.数据不太安全
post(请求行、请求头、请求体)
1.请求参数不在地址栏显示(请求体)
2.请求参数大小没有限制
3.数据相对安全
(上传文件和表单要用post,其他请求两种都可以)
绝大部分的请求都是get请求,如:
<a href="xxx">abc</a>
<link href="out.css"></link>
<img src="xx.png" />
<script src="out.js"></script>
<form method="get"></form>
浏览器的地址中输入地址,也是get请求
对于form如果是method="post",表示发出post请求
请求行:请求方式 请求路径 协议/版本号
例:
POST /day07_myapp/static/login.html HTTP/1.1
GET /day07_myapp/static/login.html?username=jack&password=123 HTTP/1.1
请求头:请求头名称:请求头的值//例:Host: localhost:8080这种
请求体:参数名=参数值&参数名=参数值…
例:username=jack&password=123
注意:get方式没有请求体,post方式才有。
http状态码
http状态码详细版:传送门
200 OK:客户端请求成功。
400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。
403 Forbidden:服务器收到请求,但是拒绝提供服务。
404 Not Found:请求资源不存在,举个例子:输入了错误的URL。
500 Internal Server Error:服务器发生不可预期的错误。
503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常,
举个例子:HTTP/1.1 200 OK(CRLF)。
5.4 http请求之get方式
get:请求行、请求头
5.4 http请求之post方式
post:请求行、请求头、请求体
5.5 res响应
在node.js中,http协议如果不设置响应头,中文的话在客户端浏览器是会乱码的。
res.writehead
书写响应头信息第一个参数是状态码
,第二个参数是一个对象content-type
表示内容类型,然后可选,告诉浏览器我发给你的数据是什么类型的。res.setHeader
方法就少了第一个参数。它们俩个都是用来设置响应头的。
res.end()
服务端向页面写入的数据,它所支持的数据类型是二进制数据,字符串类型的数据,如果我们要在页面上显示其他类型的数据就要进行上面的修改响应头信息。
response.writeHead(statusCode, [reasonPhrase], [headers])
接收参数:statusCode, [reasonPhrase], [headers]
第一个是HTTP状态码,如200(请求成功),404(未找到)等。
第二个是告诉浏览器发送的数据类型 html css jpg等。
第三个就是具体发送的是什么数据。
res.writeHead()
必须在res.end()
之前调用。
如果两者同时存在(没必要),要先写res.setHeader()
,后写res.writeHead()
,且res.writeHead()
优先。
//设置响应头
res.setHeader('Content-type', 'text/plain;charset=utf-8')
res.writeHead(200,{'Content-type':'text/plain;charset=utf-8'})//识别纯文本格式
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});//识别HTML结构,编码格式是UTF-8
res.writeHead(200,{'Content-Type':'image/jpg;charset=utf-8'});//识别图片格式 图片不需要指定编码(utf-8),一般只为字符数据才指定编码
res.writeHead(200,{'Content-Type':'text/css;charset=utf-8'});//识别css样式
res.write();//""内写什么输出什么,格式被 writehead 确定
res.end();//结束响应
res.send();express自带的,可以自动分配Content-Length
HTTP响应标头字段(除非事先定义)。
res.send([body|status], [body])
既可以直接发送内容,也可以第一个参数状态,第二个参数内容。
如果直接发送内容的话,状态会被自动补全;
super关键字用于访问和调用一个对象的父对象上的函数。
7 路由(原生node)
const http = require("http");
//引入模块
const url = require("url")
const qs = require("querystring")
//创建服务器
const server = http.createServer();
//监听request事件
server.on("request", (req, res) => { //当请求过来就会触发监听器
//req请求对象 :url、method(请求方法get/post)
//res响应对象
// console.log(req.method.toLowerCase());// 获取请求方法并小写 get或者post
let method = req.method.toLowerCase();
let urlObj = url.parse(req.url);
let path = urlObj.pathname;//赋值名path路径
let params = '';//接收的数据默认为空
if (method === 'get') {
//method方法如果是get请求 处理get请求
//get请求的数据在url中
//console.log(req.url);//这个url是请求数据http://localhost:3001/?name='wc'&pwd='123' 问号?后面的内容
// console.log(url.parse(req.url));//解析url模块
// console.log(urlObj.pathname);// 获取路径名
// console.log(urlObj.query);// 获取请求参数
// console.log(qs.parse(urlObj.query));// 获取请求参数 通过parse方法变成对象才能拿到
let params = qs.parse(urlObj.query)//赋值名params请求参数
if (path === '/login') {//这个是路径是放在端口后面的 这样跳转链接时确认每一个页面内容
//代表处理login登录请求
console.log("get处理登录请求,参数是:" + params.name);
} else if (method === 'reg') {
//代表处理reg注册请求
console.log("get处理注册请求,参数是:" + params.name);
}
} else if (method === 'post') {
//method方法如果是post请求 处理post请求
//post请求是把请求放在请求体里传给服务器 所以需要监听两个事件
req.on("data", chunk => {//data事件是指每个请求过来的数据(客户端的数据像流水一样流到服务器)每流一点都会触发data事件
// chunk是指每个数据(每滴水)
//定义变量接收数据 第17行
params+=chunk;
})
req.on("end",()=>{//end事件 {}内就可以拿到数据了
if (path === '/login') {//这个是路径是放在端口后面的 这样跳转链接时确认每一个页面内容
//代表处理login登录请求
console.log("post处理登录请求,参数是:" + qs.parse(params).name);//parse变为对象 然后.name获取值
} else if (method === '/reg') {
//代表处理reg注册请求
console.log("post处理注册请求,参数是:" + qs.parse(params).name);
}
})
}
res.end();//结束响应 不然服务器不会停
})
// 端口0~65535 一般使用1024~65535;
server.listen(3001, () => {
//监听端口
console.log("服务器运行起来了,端口是3001~");
})
8 异步代码解决方案
8.1 异步代码
代码书写顺序
和代码的执行顺序
是一样
的,这样的代码叫同步代码
,在JS中,大部分的代码都是同步代码
。
代码的书写顺序
和代码的执行顺序不一样
,这样的代码叫异步代码
。
在执行代码时,先执行同步代码
,同步代码
执行完毕后,再执行异步代码
。
异步代码特点:不会立即执行,需要满足某种条件才会执行。
常见的异步代码:
1)定时器
2)事件绑定
3)ajax发请求
4)异步读文件操作
…
8.2 异步代码实现靠回调函数
回调函数:先不调用,回头调用。
定时器这个异步代码,实现就是靠回调函数。
// setTimeout() 是一个函数 调用函数
// setTimeout的参数也是一个函数
// 如果一个函数的参数也是函数,那么作为参数的函数叫回调函数
setTimeout(() => {
console.log("我是一个定时器")
}, 3000)
再看代码:
//DOM2的事件绑定,也是异步代码,靠的也是回函数实现的。
console.log("start")
let btn = document.getElementById("btn");
// addEventListener()是一个函数
// 参数1:click 字符串
// 参数2:函数
// 如果一个函数作为另一个函数的参数,作为参数的函数叫回调函数
btn.addEventListener("click", function () {
console.log("我被点击了")
})
console.log("end")
再看代码:
let fs = require("fs"); // 引入fs模块
console.log("start")
// readFile的第三个参数也是一个回调函数
// readFile异步代码实现也是靠回调函数实现的
fs.readFile("./name.txt", "utf-8", (err, data) => {
if (err) return;
console.log(data.trim()); // age.txt.
console.log("---------------")
fs.readFile(data.trim(), "utf-8", (err, data) => {
if (err) return;
console.log(data); // 100
})
})
console.log("end")
总结:上面异步代码,靠回调函数。
但是,回调函数不一定都是异步的。如下的代码就是同步代码:
console.log("start")
function fn(callback) {
callback(); // 回调函数
} f
n(function () {
console.log("....")
});
console.log("end")
回调地狱
回调地域,表示回调函数中嵌套回调函数。
利用回调函数实现异步有什么不足:如果层数非常多,就会出现回调地域,代码的可读性不好。
9 动态网页
静态资源:html文件,css文件,img文件…
服务端渲染:
在服务器端,通过模板引擎技术
,把网页中需要替换数据的地方,替换了,替换后,得到一张网页,这个网页上的数据就是真实数据,服务器把这个网页响应给浏览器,浏览器得到的网页上的数据就是一个真实数据。
在使用服务端渲染技术:模板引擎。
客户端渲染:
在客户端,拿到数据后自己去渲染。在客户端替换是客户端渲染。
ejs模块是项目依赖,开发时需要,项目创建时也需要。