HTTP响应原理
1. 服务器端基础概念
1.1 网站的组成
网站应用程序主要分为两大部分:客户端和服务器端
客户端:在浏览器中运行的部分,用户看到并与之交互的界面程序
服务器端:在服务器中运行的部分,负责存储数据和处理应用逻辑

1.2 Node网站服务器
能够提供网站访问服务的机器就是网站服务器,它能够接收客户端的请求,能够对请求做出响应

1.3 IP地址
互联网中设备的唯一标识
IP是 Internet Protocol Address 的简写,代表互联网协议地址
1.4 域名
由于IP地址难于记忆,所以产生了域名的概念,所谓域名就是平时上网所使用的网址
http://www.baidu.com => http://124.165.219.100/
虽然在地址栏中输入的是网址, 但是最终还是会将域名转换为 ip 才能访问到指定的网站服务器
1.5 端口
端口是计算机与外界通讯交流的出口,用来区分服务器电脑中提供的不同的服务

1.6 URL
统一资源定位符,又叫URL(Uniform Resource Locator),是专为标识 Internet 网上资源位置而设的一种编址方式,我们平时所说的网页地址指的即是URL
URL的组成:
传输协议: // 服务器IP或域名:端口 / 资源所在位置标识
http://www.baidu.com/news/20181018/09152238514.html
http:超文本传输协议,提供了一种发布和接收HTML页面的方法
1.7 开发过程中客户端和服务器端说明
在开发阶段,客户端和服务器端使用同一台电脑,即开发人员电脑
本机域名:localhost
本地IP:127.0.0.1

2. 创建 web 服务器
const http = require('http'); // 用于创建网站服务器的模块
const url = require('url'); // 用于处理 url 地址模块
const app = http.createServer(); // app 对象就是网站服务器对象
// request 当客户端有请求来时
// 请求消息 req 响应消息 res
app.on('request', (req, res) => {
res.end('<h2>hello user</h2>');
});
app.listen(3000); // 监听端口
console.log('网站服务器启动成功');
注意:每次请求服务器如果没有响应就一直处于等待当中(转圈)
3. HTTP 协议
3.1 HTTP 协议的概念
超文本传输协议:
英文:HyperText Transfer Protocol,缩写:HTTP
规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器架构工作,是客户端(用户)和服务器端(网站)请求和应答的标准

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

3.3 请求报文
-
请求方式 (Request Method)
- GET:请求数据
- POST:发送数据
-
请求地址 (Request URL)
app.on('request', (req, res) => {
req.headers // 获取请求报文
req.url // 获取请求地址
req.method // 获取请求方法
});
3.4 响应报文
- HTTP状态码
- 200 请求成功(默认)
- 400 客户端请求有语法错误
- 404 请求的资源没有被找到
- 500 服务器端错误
- 内容类型
- text/plain(默认纯文本)
- text/html
- text/css
- application/javascript
- image/jpeg
- application/json
app.on('request', (req, res) => {
res.writeHead(200, { // 设置响应报文
'Content-Type': 'text/html;charset=utf8‘
});
});
4. HTTP请求与响应处理
4.1 请求参数
客户端向服务器端发送请求时,有时需要携带一些客户信息,客户信息需要通过请求参数的形式传递到服务器端,比如登录操作

4.2 GET请求参数
参数被放置在浏览器地址栏中
例:http://localhost:3000/index?name=lisi&age=18
参数获取需要借助系统模块 url,url 模块用来处理 url 地址
const url = require('url'); // 用于处理 url 地址模块
const http = require('http'); // 用于创建网站服务器的模块
const app = http.createServer(); // app 对象就是网站服务器对象
app.on('request', (req, res) => {
// 参数1:要解析的 url 地址
// 参数2:是否将查询参数解析成对象形式
let { query, pathname } = url.parse(req.url, 1);
console.log(query.name); // lisi
console.log(query.age); // 18
});
app.listen(3000); // 监听端口
4.3 POST请求参数
- 参数被放置在请求体(报文)中进行传输
- 获取 POST 参数需要使用 data 事件和 end 事件
- 使用 querystring 系统模块将字符串格式转换为对象格式
const http = require('http'); // 用于创建网站服务器的模块
const app = http.createServer(); // app 对象就是网站服务器对象
const querystring = require('querystring'); // 处理请求参数模块
app.on('request', (req, res) => {
let postParams = ''; // 因参数传递可能不是一次性传完的,需要累加收集
// data 当请求参数传递的时候触发事件
req.on('data', params => {
postParams += params;
});
// end 当参数传递完成的时候触发事件
req.on('end', () => {
console.log(postParams); // username=wzq&password=123
console.log(querystring.parse(postParams)); // 处理成对象格式的
})
res.end('ok');
});
app.listen(3000); // 监听端口
<!-- method: 指定当前表单提交的方式 -->
<!-- action: 指定当前表单提交的地址 -->
<form method="post" action="http://localhost:3000">
<!-- name 属性用于对提交到服务器后的表单数据进行标识 -->
<input type="text" name="username">
<input type="password" name="password">
<input type="submit">
<!-- 注意:只有设置了 name 属性的表单元素才能在提交表单时传递它们的值 -->
</form>
4.4 路由
路由是指客户端请求地址与服务器端程序代码的对应关系
简述:就是请求什么响应什么

4.5 静态资源
服务器端不需要处理,可以直接响应给客户端的资源就是静态资源,如:HTML、CSS、JavaScript、image 文件
例:http://www.itcast.cn/images/logo.png
4.6 动态资源
相同的请求地址不同的响应资源,这种资源就是动态资源
http://www.itcast.cn/article?id=1http://www.itcast.cn/article?id=2
可能就是两个页面
4.7 客户端请求途径
- GET 方式
- 浏览器地址栏
- link 标签的 href 属性
- script 标签的 src 属性
- img 标签的 src 属性
- Form 表单提交
- POST 方式
- Form 表单提交
图图图
5. Node.js 异步编程
5.1 同异步 API
同步API:只有当前 API 执行完成后,才能继续执行下一个 API
console.log('1');
console.log('2');
异步API:当前 API 的执行不会阻塞后续代码的执行
console.log('1');
setTimeout(
() => { console.log('3');
}, 2000);
console.log('2');
5.2 同异步 API 的区别( 获取返回值 )
// 同步:可以从返回值中拿到 API 执行的结果
function sum (n1, n2) {
return n1 + n2;
}
const result = sum (10, 20);
// 异步:不能直接拿到返回值(想要拿到结果必须通过回调函数返回)
function getMsg () {
setTimeout(function () {
return { msg: 'Hello' }
}, 2000);
}
const msg = getMsg ();
console.log(msg); // undefined
5.3 回调函数
自己定义函数让别人去调用
// getData 函数定义
function getData(callback) {
callback('123')
}
// getData 函数调用
getData(function(n) {
console.log('callback函数被调用了')
console.log(n) // 123
});
5.4 使用回调函数获取异步 API 执行结果
function getMsg (callback) {
setTimeout(function () {
callback ({ msg: 'Hello' })
}, 2000);
}
getMsg (function (msg) {
console.log(msg); // hello
});
5.5 同异步 API 的区别(代码执行顺序)
同步 API:从上到下依次执行,前面代码会阻塞后面代码的执行
for (var i = 0; i < 100000; i++) {
console.log(i);
}
console.log('最后输出的代码');
异步 API:不会等待 API 执行完成后再向下执行代码
console.log('1'); // 1
setTimeout(() => { console.log('4')}, 2000);
setTimeout(() => { console.log('3')}, 0);
console.log('2'); // 2
5.6 代码执行顺序分析
图图图
5.7 Node.js 中的异步 API
// 第一种:读取文件
fs.readFile('./demo.txt', (err, result) => {});
// 第二种:事件回调
var server = http.createServer();
server.on('request', (req, res) => {});
如果异步 API 后面代码的执行依赖当前异步 API 的执行结果,但实际上后续代码在执行时异步 API 还没有返回结果,这个问题要怎么解决呢?
fs.readFile('./demo.txt', (err, result) => {});
console.log('文件读取结果');
需求:依次读取A文件、B文件、C文件
fs.readFile('./1.txt', 'utf8', (err, result1) => {
console.log(result1) // 1
fs.readFile('./2.txt', 'utf8', (err, result2) => {
console.log(result2) // 2
fs.readFile('./3.txt', 'utf8', (err, result3) => {
console.log(result3) // 3
})
})
});
多次回调函数嵌套会让代码很难维护,称为回调地狱
5.8 Promise
Promise 出现的目的是解决 Node.js 异步编程中回调地狱的问题
Promise 是个构造函数,参数内有以下两个函数,当异步 API 执行:
- resolve:把成功结果通过参数传递出去
- reject:把失败结果通过参数传递出去
Promise 有两个方法获取异步函数执行结果,调用异步函数再链式调用:
- then 方法:获取读取成功的内容
- catch 方法: 获取错误信息
let promise = new Promise((resolve, reject) => {
fs.readFile('1.txt', 'utf8', (err, result) => {
if (err != null) { // 如果有错误信息
reject(err); // 传入错误信息
} else { // 如果读取成功
resolve(result); // 传入读取内容
}
});
});
promise.then((result) => { // 获取读取成功的内容
console.log(result);
})
.catch((err) => {
console.log(err); // 获取读取失败的内容
});
注意:获取时要设置形参接收传出的内容
5.9 异步函数 async
异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了
async 关键字:
- 普通函数定义前加 async 关键字,就变成异步函数
- 异步函数默认返回 promise 对象
- return 关键字代替了 resolve 方法,在异步函数内部使用 return 关键字进行结果返回,结果会被包裹到 promise 对象中
- 在异步函数内部使用 throw 关键字抛出程序异常(遇到后不会再向下执行)
await 关键字:
- await 关键字只能出现在异步函数中
- await 后面只能写 promise 对象 写其他类型的 API 是不可以的
- await 关键字可是暂停异步函数向下执行,直到 promise 返回结果
文章版权归作者所有,未经允许请勿转载。

浙公网安备 33010602011771号