Node.js基础:第三篇
- 客户端:在浏览器中运行的部分,就是用户看到并与之交互的界面程序。使用HTML、CSS、JavaScript构建。
- 服务器端:在服务器中运行的部分,负责存储数据和处理应用逻辑。
1.2-Node网站服务器
能够提供网站访问服务的机器就是网站服务器,它能够接收客户端的请求,能够对请求做出响应。
1.3-IP地址
互联网中设备的唯一标识。
IP是Internet Protocol Address的简写,代表互联网协议地址。
1.4-域名
由于IP地址难于记忆,所以产生了域名的概念,所谓域名就是平时上网所使用的网址。
http://www.baidu.com => http://39.156.66.14/
虽然在地址栏中输入的是网址, 但是最终还是会将域名转换为ip才能访问到指定的网站服务器。
1.5-端口
端口是计算机与外界通讯交流的出口,用来区分服务器电脑中提供的不同的服务。
1.6-URL
统一资源定位符,又叫URL(Uniform Resource Locator),是专为标识Internet网上资源位置而设的一种编址方式,我们平时所说的网页地址指的即是URL。
URL的组成:传输协议://服务器IP或域名:端口/资源所在位置标识
https://www.baidu.com/index.html
1.7-开发过程中客户端和服务器端
在开发阶段,客户端和服务器端使用同一台电脑,即开发人员电脑。
本机域名:localhost
本地IP :127.0.0.1
第二章:创建web服务器
// 1. 导入http模块const http = require("http");
// 2. 创建web服务器对象
const app = http.createServer();
// 3. 给服务器注册request事件,监听用户请求,并作出响应
app.on("request", (req, res) => {
// 响应客户端
res.end("Hello!")
});
// 4. 监听端口4000
app.listen(4000);
在本地浏览器总:输入地址→localhost:4000
第三章:HTTP协议
3.1-概念
超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器架构工作,是客户端(用户)和服务器端(网站)请求和应答的标准。
3.2-报文
在HTTP请求和响应的过程中传递的数据块就叫报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式。
3.3-请求报文
请求方式
- get
- post
请求地址
const http = require("http");const app = http.createServer();
app.on("request", (req, res) => {
// 获取请求报文
console.log(req.headers);
// 获取请求的路径
console.log(req.url);
// 获取请求的方式
console.log(req.method);
});
app.listen(4000);
3.4-响应报文
HTTP状态码
200 请求成功
404 请求的资源没有被找到
500 服务器端错误
400 客户端请求有语法错误
内容类型
text/html
text/css
application/javascript
image/jpeg
application/json
代码演示
const http = require("http");const app = http.createServer();
app.on("request", (req, res) => {
// 设置响应报文(状态码和响应的内容类型与编码)
res.writeHead(200, {
"Content-Type":"text/html;charset=utf-8"
})
res.end("<h1>你好!</h1>");
});
app.listen(4000);
第四章:HTTP请求与响应处理
4.1-请求参数
客户端向服务器端发送请求时,有时需要携带一些客户信息,客户信息需要通过请求参数的形式传递到服务器端,比如查询操作、登录操作等。
4.2-GET请求参数
参数被放置在浏览器地址栏中,例如:http://localhost:3000/?id=1&type=2
参数获取需要借助系统模块url
,url模块用来处理url地址
const http = require("http");// 【导入url模块】
const url = require("url");
const app = http.createServer();
app.on("request", (req, res) => {
// 【将req.url转换为对象,并解构出 [请求路径] 和 [对象格式的请求参数]】
let {query,pathname} = url.parse(req.url, true);
// 请求路径
console.log(pathname);
// 请求参数对象
console.log(query);
});
app.listen(3000);
4.3-POST请求参数
参数被放置在请求体中进行传输
获取POST参数需要使用data事件
和end事件
使用querystring系统模块
将参数转换为对象格式
表单:
<form action="http://localhost:4000" method="POST"> 用户名:<input type="text" name="username">
密码:<input type="password" name="pwd">
<input type="submit">
</form>
node服务
const http = require("http");// 导入querystring模块
const querystring = require("querystring");
const app = http.createServer();
app.on("request", (req, res) => {
// 定义变量,接收客户端post请求参数
let paramsStr = "";
// 注册data事件接收参数数据
req.on("data", (chunk) => { paramsStr += chunk });
// 注册end事件,接收完毕后的处理
req.on("end", () => {
let paramsObj = querystring.parse(paramsStr);
console.log(paramsObj);
});
});
app.listen(4000);
4.4-路由
http://localhost:3000/index
http://localhost:3000/login
路由是指客户端请求地址与服务器端程序代码的对应关系。简单的说,就是请求什么响应什么。
const http = require("http");const url = require("url");
const app = http.createServer();
app.on("request", (req, res) => {
// 获取请求的路径
let { pathname } = url.parse(req.url, true);
// 设置响应头
res.writeHead(200, { "content-Type": "text/html;charset=utf-8" });
// 处理路由
if (pathname == "/index.html" || pathname == "/") {
res.end("<h1>首页</h1>");
} else if (pathname == "/list.html") {
res.end("<h1>列表页面</h1>");
} else {
res.writeHead(404, { "content-Type": "text/html;charset=utf-8" });
res.end("<h1>页面不存在</h1>");
}
});
app.listen(4000);
4.5-静态资源
服务器端不需要处理,可以直接响应给客户端的资源就是静态资源,例如CSS、JavaScript、image文件。
https://m.360buyimg.com/babel/jfs/t1/36002/35/9106/3311/5cd4f1bdE06ff07ed/9570fdd46ecd3a76.png
const http = require("http");const url = require("url");
const path = require("path");
const fs = require("fs");
// 导入第三方模块mime
const mime = require("mime");
const app = http.createServer();
app.on("request", (req, res) => {
// 获取请求的路径
let { pathname } = url.parse(req.url, true);
// 拼接服务器上文件的物理路径
let realPath = path.join(__dirname, "public", pathname);
// 获取请求的资源类型
let type = mime.getType(realPath);
console.log(realPath);
// 读取服务器本地文件
fs.readFile(realPath, (err, data) => {
if (err) {
res.writeHead(404,{"Content-type":type+";charset=utf-8"});
res.end("访问资源不存在");
return;
}
res.writeHead(200);
res.end(data);
});
});
app.listen(4000);
4.6-动态资源
相同的请求地址不同的响应资源,这种资源就是动态资源。
https://www.baidu.com/s?wd=美女
https://www.baidu.com/s?wd=帅哥
4.7-客户端请求途径
- GET方式
- 浏览器地址栏
- link标签的href属性
- script标签的src属性
- img标签的src属性
- Form表单提交
- POST方式
- Form表单提交
第五章:Node异步编程
5.1-同步API, 异步API
同步API:只有当前API执行完成后,才能继续执行下一个API
console.log("before"); console.log("after");
异步API:当前API的执行不会阻塞后续代码的执行
console.log("before");setTimeout(
() => { console.log("last");
}, 2000);
console.log("after");
区别1:同步API, 异步API的区别(返回值):
// 【同步】function sum (n1, n2) {
return n1 + n2;
}
const result = sum (10, 20);
// 结果:30
// 【异步】
function getMsg () {
setTimeout(function () {
return { msg: "Hello Node.js" }
}, 2000);
}
const msg = getMsg ();
// 结果:undefind
区别2:同步API, 异步API的区别(代码执行顺序)
- 同步API从上到下依次执行,前面代码会阻塞后面代码的执行
- 异步API不会等待API执行完成后再向下执行代码
5.2-回调函数
回调函数的基本定义和使用
// getData函数定义 function getData (callback) {}
// getData函数调用
getData (() => {});
使用回调函数获取异步API执行结果
function getMsg (callback) { setTimeout(function () {
callback ({ msg: "Hello Node.js" })
}, 2000);
}
getMsg (function (msg) {
console.log(msg); // 结果:Hello Node.js
});
5.3-异步代码执行顺序分析
console.log("代码开始执行");setTimeout(() => {
console.log("2秒后执行的代码");
}, 2000);
setTimeout(() => {
console.log(""0秒"后执行的代码");
}, 0);
console.log("代码结束执行");
5.4-Node.js中的异步API
需求:依次读取A文件、B文件、C文件
const fs = require("fs");// 读取文件1
fs.readFile("./public/a.txt", "utf-8", function (err, data) {
console.log(data);
fs.readFile("./public/b.txt", "utf-8", function (err, data) {
console.log(data);
fs.readFile("./public/c.txt", "utf-8", function (err, data) {
console.log(data);
})
})
});
问题:回调嵌套太多,代码不易于维护
解决方案:Promise对象
5.5-Promise对象
基本使用
let p1 = new Promise((resolve, reject) => { // resolve表示执行成功后的函数
// reject表示异常时的函数
fs.readFile("./public/1.txt", "utf-8", function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
p1
// 执行成功后的操作
.then((data) => { console.log(data) })
// 发生异常时的操作
.catch((err) => { console.log(err) });
完成需求
const fs = require("fs");function p1() {
return new Promise((resolve, reject) => {
fs.readFile("./public/a.txt", "utf-8", (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
function p2() {
return new Promise((resolve, reject) => {
fs.readFile("./public/b.txt", "utf-8", (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
function p3() {
return new Promise((resolve, reject) => {
fs.readFile("./public/c.txt", "utf-8", (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
p1()
.then((data) => {
console.log(data);
return p2();
})
.then((data) => {
console.log(data);
return p3();
})
.then((data) => {
console.log(data);
})
5.6-异步函数
异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。
关键字:async
语法:async function fn () {}
或 const fn = async () => {};
- 普通函数定义前加async关键字 普通函数变成异步函数
- 异步函数默认返回promise对象
- 在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替了resolve方法
- 在异步函数内部使用throw关键字抛出程序异常
- 调用异步函数再链式调用then方法获取异步函数执行结果
- 调用异步函数再链式调用catch方法获取异步函数执行的错误信息
let fn1 = async () => { // throw "异常";
return "success";
};
fn1()
.then((data) => { console.log(data) })
.catch((err)=>{console.log(err)})
关键字:await
- await关键字只能出现在异步函数中
- await promise await后面只能写promise对象 写其他类型的API是不不可以的
- await关键字可是暂停异步函数向下执行 直到promise返回结果
完成需求
const fs = require("fs");// 用于改造现有的异步函数api,让其返回promise对象,从而支持异步函数的语法
const promisify = require("util").promisify;
let readFile = promisify(fs.readFile);
async function run() {
let f1 = await readFile("./public/1.txt", "utf-8");
let f2 = await readFile("./public/2.txt", "utf-8");
let f3 = await readFile("./public/3.txt", "utf-8");
console.log(f1);
console.log(f2);
console.log(f3);
}
run();
以上是 Node.js基础:第三篇 的全部内容, 来源链接: utcz.com/z/513714.html