服务器端

本文最后更新于:2024年11月17日 晚上

1.服务器端基础概念

1.1URL

统一资源定位符,又叫 URL(Uniform Resource Locator),是专门为标识 Internet 网上资源位置而设的一种编址方式,我们平时所说的网页地址指的即是 URL

URL 的组成

传输协议:服务器 ip 或域名:端口资源所在位置标识

http://www.badspider.top/page/1024.html

http:超文本传输协议,提供了一种发布和接受 HTML 页面的方法

关于端口,我们输入网址的时候是不需要写的,因为浏览器在请求的时候会默认加上 80 端口

1.2 开发过程中客户端和服务器端说明

在开发阶段,客户端和服务器端使用同一台电脑,即开发人员电脑

​ 开发人员电脑

客户端(浏览器)
服务器端(Node)

本机域名:localhost

本地 ip:127.0.0.1

2.创建 web 服务器

2.1 创建 web 服务器

1
2
3
4
5
6
7
8
9
10
11
12
//引用系统模块
const http = require("http");
//创建web服务器
const app = http.createSever();
//当客户端发送请求的时候
app.on("request", (req, res) => {
//响应
res.end("<h1>hi,user</h1>");
});
//监听3000端口
app.listen(3000);
console.log("服务器已经启动,监听3000端口,请访问localhost:3000");

2.2Http 协议的概念

报文

在 http 请求和响应的过程中传递的数据块就叫报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式

QQ截图20210408083639

2.3 请求报文

1.请求方式(Request Method)

  • GET 请求数据

  • POST 发送数据 (更安全)

    2.请求地址(Request URL)

1
2
3
4
5
app.on("request", (req, res) => {
req.headers; //获取请求报文
req.url; //获取请求地址
req.method; //获取请求方法
});

2.4 响应报文

  1. http 状态码

    • 200 请求成功
    • 404 请求的资源没有被找到
    • 500 服务器端错误
    • 400 客户端请求有语法错误
  2. 内容类型

    • text/html
    • text/css
    • application/javascript
    • image/jepg
    • application/ json

3.HTTP 请求与响应处理

3.1 请求参数

客户端向服务器端发送请求时,有时需要携带一些客户信息,客户信息需要通过请求参数的形式传递到服务器端,比如登录操作

3.1.1 GET 请求参数

问号后面的就是参数,如果传递多个用&分隔

3.1.2 POST 请求参数

method: 指定当前表单提交的方式

action: 指定当前表单提交的地址

post 参数是通过事件的方式接收的

  1. data 当请求参数传递的时候触发 data 事件
  2. end 当参数传递完成的时候触发 end 事件
1
2
3
4
5
6
7
8
9
10
11
//当客户端有请求来的时候
app.on("request", (req, res) => {
let postParams = "";
req.on("data", (params) => {
postParams += params;
});
req.on("end", () => {
console.log(postParams);
});
res.end("ok");
});

3.2 路由

路由是指客户端请求地址与服务器端程序代码的对应关系。简单的说,就是请求什么响应什么QQ截图20210409091759

1
2
3
4
5
6
7
8
9
10
11
12
//当客户端发来请求的时候
app.on("request", (req, res) => {
//获取客户端的请求路径
let { pathname } = url.parse(req.url);
if (pathname == "/" || pathname == "/index") {
res.end("welcome to index");
} else if (pathname == "/list") {
res.end("welcome to list ");
} else {
res.end("sorry,404 not found");
}
});

3.3 静态资源

服务器端不需要处理,可以直接响应给客户端的资源就是静态资源,例如 CSS,Javascript,image 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const http = require("http");
const url = require("url");
const path = require("path");
const fs = require("fs");

var app = http.createServer();

app.on("request", (req, res) => {
res.writeHead(200, {
"content-type": "text/html;charset=utf8",
});
//获取用户的请求路径
let pathname = url.parse(req.url).pathname;
//将用户的请求路径转换为实际的服务器硬盘路径
let readpath = path.join(__dirname, "public" + pathname);
//读取文件
fs.readFile(readpath, (error, result) => {
if (error != null) {
res.end("文件读取失败");
return;
}
res.end(result);
});
});

app.listen(3000);
console.log("It's working");

3.4 动态资源

相同的请求地址不同的响应资源,这种资源就是动态资源

4.Node.js 异步编程

4.1 同步 API,异步 API

同步 api:只有当前 api 执行完成后,才能继续执行下一个 api

1
2
console.log("before");
console.log("after");

异步 api:当前 api 的执行不会阻塞后续代码的执行

1
2
3
4
5
console.log('before')
setTimeout(
()=>{console.log('last')}
),2000)
console.log('after')

4.2 同步 api,异步 api 的区别(获取返回值)

同步 api 可以从返回值中拿到 api 执行的结果,但是异步 api 是不可以的

1
2
3
4
5
//同步
function sum(s1, s2) {
return s1 + s2;
}
const result = sum(10, 20);
1
2
3
4
5
6
7
8
9
//异步
function getMsg() {
setTimeout(function () {
return (msg: "hello node.js");
}, 2000);
}

const msg = getMsg();
console.log(msg); //undefined

4.3 回调函数

自己定义函数让别人去调用

1
2
3
4
//getData 函数定义
function getData(callback) {}
//getData 函数调用
getData(() => {});

4.4 同步 api,异步 api 的区别(代码执行顺序)

同步 api 从上到下依次执行,前面代码会阻塞后面代码的执行

1
2
3
4
for (var i = 1; i < 1000; i++) {
console.log(i);
}
console.log("it's ending");

异步 api 不会等待 api 执行完成后再向下执行代码

1
2
3
4
5
6
7
8
console.log("代码开始执行");
setTimeout(() => {
console.log("ssss");
}, 2000);
setTimeout(() => {
console.log("aaa");
}, 0);
console.log("it's ending");

屏幕截图 2021-04-09 194140

会先执行完同步代码再去回调函数队列中拿回调函数执行

4.5Node.js 中的异步 api

fs.readFile('./demon.text',(err,result)=>{})

回调地狱

1
2
3
4
5
6
7
8
9
10
11
const fs = require("fs");

fs.readFile("./1.text", "utf8", (err, result1) => {
console.log(result1);
fs.readFile("./2.text", "utf8", (err, result2) => {
console.log(result2);
fs.readFile("./3.text", "utf8", (err, result3) => {
console.log(result3);
});
});
});

4.6Promise

Promise 出现的目的是解决 Node.js 异步编程中回调地狱的问题

1
2
3
4
5
6
7
8
9
10
11
12
let promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
if(true){
resolve({name:'张三'})
}
else {
reject("失败了")
}
},2000)
})
promise.then(result=>console.log(result)) //{name:'张三'}
.catch(error=>console(error)) //失败了

4.7 异步函数

异步函数是异步编程语法的终极解决方案,它可以让外面将异步代码写出同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了

const fn = async()=>{}

async function fn(){}

1.在普通函数定义的前面加上 async 关键字,普通函数就变成了异步函数

2.异步函数默认的返回值是 promise 对象

3.在异步函数内部使用 return 关键字进行结果返回 结果会被包裹的 promise 对象中 return 关键字代替了 resolve 方法

4.在异步函数内部使用 throw 关键字抛出异常

5.调用异步函数再链式调用 then 方法获取异步函数执行结果

6.调用异步函数再链式调用 catch 方法获取异步函数执行的错误信息

7.await 关键字只能出现在异步函数中

8.await promise await 后面只能写 promise 对象 写其他类型的 api 是不可以的

9.await 关键字可以暂停异步函数向下执行 直到 promise 返回结果

QQ截图20210409202447

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const fs = require("fs");
//改造现有异步函数api 让其返回promise对象
const promisify = require("util").promisify;
const readFile = promisify(fs.readFile);

async function run() {
let r1 = await readFile("./1.txt", "utf8");
let r2 = await readFile("./2.txt", "utf8");
let r3 = await readFile("./3.txt", "utf8");
console.log(r1);
console.log(r2);
console.log(r3);
}
run();

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!