请求响应原理及HTTP协议,请求报文与响应报文

一、服务器端基础概念

1.1 网站的组成

网站应用程序主要分为两大部分:客户端和服务器端。
客户端:在浏览器中运行的部分,就是用户看到并与之交互的界面程序。使用HTML、CSS、JavaScript构建。
服务器端:在服务器中运行的部分,负责存储数据和处理应用逻辑。

1.2 Node网站服务器

能够提供网站访问服务的机器就是网站服务器,它能够接收客户端的请求,能够对请求做出响应
一台电脑需要安装Node代码运行环境,使用Nodejs创建一个能接收对象和响应请求的对象,就是Node网站服务器(可以没有显示器鼠标键盘,只有一个主机)
电脑 ➡️ Node ➡️ 响应请求的对象

1.3 IP地址

互联网中设备的唯一标识。
IP是Internet Protocol Address的简写,代表互联网协议地址

1.4 域名

由于IP地址难于记忆,所以我们一般不会使用IP地址直接访问网站。于是产生了域名的概念,所谓域名就是平时上网所使用的网址
http://www.hellocode.com => http://136.168.215.101/
虽然在地址栏中输入的是网址, 但是最终还是会将域名转换为ip才能访问到指定的网站服务器。

1.5 端口

端口是计算机与外界通讯交流的出口,用来区分服务器电脑中提供的不同的服务。(比如web server和email server)

1.6 URL

统一资源定位符,又叫URL(Uniform Resource Locator),是专为标识Internet网上资源位置而设的一种编址方式,我们平时所说的网页地址指的即是URL。
URL的组成
传输协议://服务器IP或域名:端口/资源所在位置标识
https://localhost:8080/news/789.html

  • http:超文本传输协议。是一个基于请求与响应、无状态的、应用层的协议,常基于TCP/IP协议传输数据,互联网上应用最为广泛的一种网络协议,所有的WWW文件都必须遵守这个标准。设计 HTTP 的初衷是为了提供一种发布和接收HTML页面的方法。
  • https:是身披SSL外壳的 HTTP。一种通过计算机网络进行安全通信的传输协议,经由HTTP进行通信,利用SSL/TLS建立全信道,加密数据包。HTTPS使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私与完整性。

PS:TLS是传输层加密协议,前身是SSL协议,由网景公司1995年发布,有时候两者不区分。

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

在开发阶段,客户端和服务器端使用同一台电脑,即开发人员电脑。
客户端:浏览器
服务器端:Node.js
本地域名:localhost
本地IP:127.0.0.1

二、创建Web服务器

// 用于创建网站服务器的模块
const http = require('http');
// 用于处理url地址
const url = require('url');
// app对象就是网站服务器对象
const app = http.createServer();
// 当客户端有请求来的时候
app.on('request', (req, res) => {//req是请求对象 res是响应对象
  // 获取请求方式
  // req.method
  console.log(req.method);
    
  // 获取请求地址
  // req.url
  console.log(req.url);
    
  // 获取请求报文信息
  // req.headers
  console.log(req.headers['accept']);
    
  res.writeHead(200, {
    'content-type': 'text/html;charset=utf8'
  });

  console.log(req.url);
  // 1) 要解析的url地址
  // 2) 将查询参数解析成对象形式
  let { query, pathname } = url.parse(req.url, true);
  console.log(query.name)
  console.log(query.age)

  if (pathname == '/index' || pathname == '/') {
    res.end('<h2>欢迎来到首页</h2>');
  }else if (pathname == '/list') {
    res.end('welcome to listpage');
  }else {
    res.end('not found');
  }
    
  if (req.method == 'POST') {
    res.end('post')
  } else if (req.method == 'GET') {
    res.end('get')
  }

  // res.end('<h2>hello user</h2>');
});
// 监听端口
app.listen(3000);
console.log('网站服务器启动成功');

三、HTTP协议

超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器架构工作,是客户端(用户)和服务器端(网站)请求和应答的标准。

3.1 报文

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

请求报文:

请求行(request line)、请求头(header)、空行请求体(body,可选的、包含数据) 组成。一次 HTTP 请求会按顺序依次发送以上四个部分 (get 请求没有请求体)。

我们用谷歌浏览器来对照着查看:

依次点击找到请求报文
点击 View source
请求报文的一般格式
  • 请求行:请求方式(<Request Method>) 资源路径(<Request URL>) 协议/版本
    GET /users/9a996b97d637/publications?page=1&count=10 HTTP/1.1

    位置展示

    1. 常用请求方式 - Request Method:GET 请求(获取)数据|POST 发送(添加)数据(更安全)|PUT 替换(修改)数据|DELETE 删除数据
    2. 请求地址 - Request URL:端口号后面的地址。
  • 请求头:附加的用来告知服务器的一些信息,以键值对的形式出现。

以下列举部分常见属性:

请求头参数 描述
Host 目标服务器的主机名 (ip 地址或域名)
User-Agent 发起请求的客户端应用程序相关信息,如操作系统、浏览器等信息
Referer 当前文档的完整 URL
Accept (Accept) 指定客户端能接收哪些响应信息类型,如:image/jpg, text/html,专业术语称为MIME Type
Accept-Charset (Accept) 指定客户端支持哪些字符集,如 gb2312
Accept-Encoding (Accept) 指定客户端支持接收的内容编码(数据压缩)方式,如 gzip, deflate
Accept-Language (Accept) 指定客户端接受那些语言,如 zh-CN
Authorization (安全相关) 客户端提供给服务端进行权限认证的信息
Cookie (安全相关) 客户端携带的 cookie 信息(通常会存储一个sessionID,通过这个令牌让服务端鉴权)
Content-Type (响应头通用) 内容类型,请求的与实体对应的MIME信息。如果是 post 请求,会有这个参数,默认值为 application/x-www-form-urlencoded,表示请求体内容使用 url 编码
Content-Length (响应头通用) 请求体数据长度
Connection (响应头通用) 指定客户端和服务器之间请求/响应连接的类型,如:Keep-Alive 表示保持 TCP 持久连接
Transfer-Encodeing (响应头通用) 告知接收端为了报文的可靠传输,对报文使用什么样的编码格式
Cache-Control (响应头通用-缓存相关) 指定请求和响应遵循的缓存机制
If-Modified-Since (缓存相关) 服务器会用该值与所请求资源的最后修改时间作对比,如相同返回304和空响应体(节省带宽),告诉客户端资源未修改可直接读取客户端缓存;不同则返回200和最新的资源。值是上一次请求该资源时响应头的 Last-Modified
If-None-Match (缓存相关) 服务器会用该值与所请求资源的 ETag 作比较,匹配会返回304告诉客户端直接使用本地缓存即可;不一致则返回200和新资源(还有新 ETag)。同时存在时,优先级高于 If-Modified-Since
  • 空白行:请求报文用来分隔 请求头 和 请求体

Node 访问请求方法(method)、 请求地址(url) 和 请求头(headers)

const http = require('http');
const app = http.createServer();

app.on('request',(req, res) => {
  // 获取请求方式、请求地址 和请求头
  const { method, url, headers } = req;
  // 获取请求头某个属性信息
  const userAgent = headers['user-agent'];
})
  • 请求体(body):请求时携带的有效载荷数据。区别于 url 中的查询参数。可以简单地理解为,如果是 POST/PUT 请求,就有请求体。
响应报文:

状态行响应头空行响应体(数据) 组成。服务器响应时,会按顺序依次发送以上四个部分。

  • 状态行:协议/版本号 状态码 状态值(状态描述)
    如:HTTP/1.1 200 OK
    1. 状态码 (Status Code):用以表示服务器 HTTP 响应状态的 3 位数字代码:
状态码 描述
1xx 提示信息,服务器收到请求,需要请求者继续执行操作
2xx 成功,请求被成功接收并处理 200
3xx 重定向相关 304--所请求的资源未修改,客户端会直接访问这个资源的缓存,不会返回任何资源
4xx 客户端错误 404--请求的资源没有被找到 400-客户端请求存在语法错误
5xx 服务端错误,500--服务器在处理请求的过程中发生了错误 502/504--充当网关或代理的服务器,从远端服务器接收到了一个无效的请求/未及时从远端服务器获取请求
  • 响应头:类似请求头,告知客户端的附加信息,是一系列 key-value 值。

以下列举部分:
(部分通用属性已经在上面请求头部分列出,不再重复)

响应头参数 描述
Server 服务器软件名,如 Tengine
Content-Encoding 对主体执行的编码方式
Content-Type 响应主体的内容类型和字符集
Location 告知客户端实体实际上位于何处;用于重定向
Set-Cookie (安全相关) 设置和页面关联的Cookie
Proxy-Authenticate (安全相关) 来自代理服务器的质询列表
Vary (协商相关) 一个列表,内容来自于当前请求头的Key,比如Accept-Encoding、User-Agent等,用于发生相同请求的时候决定某个缓存的响应版本是否可以用来发给客户端
ETag (缓存相关) 实体标记。服务端当前资源实体特定版本的唯一标识符,只要资源有变化就会重新生成。下一次请求该资源时会将这个值放入请求头的 If-None-Match 来和服务端的 ETag 作比较。
Expires (缓存相关) 资源缓存过期时间。即客户端在这个时间前获取此资源都直接读取本地缓存,而不再向服务器请求,作用是控制请求的频率。Expires是http1.0的产物,已经被http1.1的 Cache-Control: max-age 替代,仍然存在是为了兼容性
Last-Modified (缓存相关) 这个实体最后一次被修改的时间。与请求头的 If-Modified-Since 配合使用

Vary

  1. Vary的内容来自于当前请求的请求头的Key,如Accept-Encoding、User-Agent等
  2. 缓存服务器进行某接口的请求结果数据缓存时,会将Vary一起缓存;
  3. 服务器缓存的Vary的内容会作为当前缓存数据是否可以作为请求结果返回给客户端的判断依据;
  4. 先通过响应数据中的Vary来判断当前缓存中同请求的数据的Vary是否失效,如果缓存中的Vary与服务器刚拿到的Vary不一致,则可以进行更新。
  5. 当Vary的值为“*”,意味着请求头中的所有信息都不可作为是否从缓存服务器拿数据的判断依据。

Content-Type
响应的内容类型,告知客户端你发送的数据内容类型,浏览器应以什么形式、什么编码读取这个文件(否则可能解析错误而出现乱码)。
文件类型有:text/plain(纯文本)-对应.txt、text/html-对应.html、text/css-对应.css、application/javascript-对应.js、image/jpeg-对应.jpg或.jpeg、image/png-对应.png、application/json-对应.json

res.writeHead(200,{
  'content-type':'application/json; charset=utf-8' 
})
  • 空白行:同上,用来分隔 响应头 和 数据。

  • 响应体:响应的data

3.2 请求参数

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

1. GET 请求参数

参数被放置在浏览器地址栏中,例如:http://localhost:3000/abc/xyz?name=zhangsan&age=20

  • 请求参数是?后面的部分,即name=zhangsan&age=20(通常我们称之为 查询参数)
// 系统模块 url 用来处理 url 地址
const url = require('url')

app.on('request', (req, res) => {
  // `url.parse(req.url)` 将 url 路径的各个部分解析出来并返回对象
  // 第二个参数 true表示把查询参数 (url对象的query属性值) 解析成对象格式
  let { query, pathname } = url.parse(req.url, true); // 解构赋值获取查询参数 query
  console.log(query.name) // zhangsan
  console.log(query.age) // 20
  console.log(pathname) // /abc/xyz
}
2. POST 请求参数
  • 参数被放置在请求体中进行传输(Form Data)
  • 获取POST参数需要使用 data 事件和 end 事件
  • 使用 querystring 系统模块将参数转换为对象格式
// 导入系统模块querystring 用于将HTTP参数转换为对象格式
const querystring = require('querystring');
app.on('request', (req, res) => {
  let postData = '';
  // 监听参数传输事件
  req.on('data', (chunk) => postData += chunk;);
  // 监听参数传输完毕事件
  req.on('end', () => { 
    console.log(postData);// 字符串
    console.log(querystring.parse(postData));  //把接收到参数字符串转化为对象
  }); 
  res.end('ok');
});

3.2 路由

http://localhost:3000/index
http://localhost:3000/login
路由是指客户端请求地址与服务器端程序代码的对应关系。简单的说,就是请求什么响应什么。

// 当客户端发来请求的时候
app.on('request', (req, res) => {
  // 获取请求方式
  const method = req.method.toLowerCase();
  // 获取客户端的请求路径
  // const pathname = url.parse(req.url).pathname;
  let { pathname } = url.parse(req.url);
  if (pathname == '/' || pathname == '/index') {
    res.end('欢迎来到首页');
  } else if (pathname == '/list') {
    res.end('欢迎来到列表页页');
  } else {
    res.end('抱歉, 您访问的页面出游了');
  }
});

3.3 静态资源

服务器端不需要处理,可以直接响应给客户端的资源就是静态资源,例如 CSS、JavaScript、image文件。
举例:http://localhost:8080/images/logo.png

3.4 动态资源

相同的请求地址不同的响应资源,这种资源就是动态资源。
http://localhost:8080/article?id=123
http://localhost:8080/article?id=456

3.5 客户端请求途径

  1. GET 方式
  • 浏览器地址栏访问
  • link 标签的 href 属性
  • script 标签的 src 属性
  • img 标签的 src 属性
  • Form 表单提交 (表单的默认跳转行为)
  1. POST 方式
  • Form 表单提交 (在form表单标签里写上method='post')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容