目录

简介

HTTP 协议格式

HTTP请求详解

URL 的 encode / decode机制

HTTP 请求 的 方法

GET和POST的区别

请求报头(header)

HTTP响应详解

HTTP请求响应过程中的Content-type


简介

HTTP协议(超文本传输协议HyperText Transfer Protocol),它是基于TCP协议的应用层传输协议,简单来说就是客户端和服务端进行数据传输的一种规则。

注意:客户端与服务器的角色不是固定的,一端充当客户端,也可能在某次请求中充当服务器。这取决与请求的发起端。HTTP协议属于应用层,建立在传输层协议TCP之上。客户端通过与服务器建立TCP连接,之后发送HTTP请求与接收HTTP响应都是通过访问Socket接口来调用TCP协议实现。

HTTP是一种无状态(stateless) 协议,HTTP协议本身不会对发送过的请求和相应的通信状态进行持久化处理。这样做的目的是为了保持HTTP协议的简单性,从而能够快速处理大量的事务, 提高效率。

然而,在许多应用场景中,我们需要保持用户登录的状态或记录用户购物车中的商品。由于HTTP是无状态协议,所以必须引入一些技术来记录管理状态,例如Cookie

我们平时打开一个网站,就是通过HTTP来传输数据的。

当我们在浏览器中输入一个 搜狗搜索的 “网址” (URL) 时, 浏览器就给搜狗的服务器发送了一个 HTTP 请求, 搜狗的服务器返回了一个 HTTP 响应.

这个响应结果被浏览器解析之后, 就展示成我们看到的页面内容. (这个过程中浏览器可能会给服务器发送多个 HTTP 请求, 服务器会对应返回多个响应, 这些响应里就包含了页面 HTML, CSS, JavaScript, 图片,字体等信息)

HTTP:超文本传输协议(Hyper Text Transfer Protocol)——是一个简单的请求-响应协议

所谓 “超文本” 的含义, 就是传输的内容不仅仅是文本(比如 html, css 这个就是文本), 还可以是一些其他的资源, 比如图片, 视频, 音频等二进制的数据

HTTP 协议格式

HTTP 是一个文本格式的协议. 可以通过 Chrome 开发者工具或者 Fiddler 抓包, 分析 HTTP 请求/响应的细节

思考问题: 为什么 HTTP 报文中要存在 “空行”” />

HTTP请求详解

请求行中的URL

一个URL例子

https : 协议方案名. 常见的有 http 和 https, 也有其他的类型. (例如访问 mysql 时用的
jdbc:mysql )

mp.csdn.net: 服务器地址. 此处是一个 “域名”, 域名会通过 DNS 系统解析成一个具体的 IP

端口号: 上面的 URL 中端口号被省略了. 当端口号省略的时候, 浏览器会根据协议类型自动决定使用
哪个端口. 例如 http 协议默认使用 80 端口, https 协议默认使用 443 端口.

mp_blog/creation/editor : 带层次的文件路径.

spm=1001.2101.3001.5352 : 查询字符串(query string). 本质是一个键值对结构. 键值对之间使用 & 分隔. 键和值之间使用 = 分隔

URL小结:
对于 URL 来说,它里面的结构看起来比较复杂,其实最重要的,和开发最关系紧密的,主要就是四个部分:

  • 1、IP地址 / 域名
  • 2、端口号(经常会被隐藏,充数的存在)
  • 3、带层次结构的路径
  • 4、queryString(查询字符串)

这四个最好掌握!!!!
尤其是 3 和 4 ,和我们写代码是密切相关的!
————————————————

URL 的 encode / decode机制

当query string 中如果包含了特殊字符,就需要对特殊字符进行转义。
这个转义的过程,就叫做 URLencode,反之,把转义后的内容还原回来,就叫做URLdecode。

那么为什么需要进行 encode?
其实很好理解,前面也看到了,一个 URL 里面是有很多特殊的含义的符号的。
比如:
/  : ?  &  = …这些符号都是在 URL中具有特定含义的。
万一,queryString 里面也包含这类特殊符号,就可能导致 URL 被解析失败!
比如:我们刚才说的 ?号,是用来分割 路径 和 查询字符串。
如果前面 和 后面都存在 问号,那完蛋。
服务器收到这条请求,就懵逼了,到底那个问号后是 查询字符串?它就会产生误会。
为了消除歧义,就规定了,一旦 queryString中遇到了这些符号,就将其转义
————————————————

HTTP 请求 的 方法

前面讲 HTTP 请求部分的时候,就涉及到:GET 和 POST。
get:就是 得到 / 获得 一个东西。
POST:就是 向服务器 传递 / 发送 一个东西。

HTTP 协议的方法非常多!
但是,最最最常用的,也就是 GET 和 POST。

常见的方法

GET方法

GET 是最常用的 HTTP 方法. 常用于获取服务器上的某个资源.
在浏览器中直接输入 URL, 此时浏览器就会发送出一个 GET 请求.
另外, HTML 中的 link, img, script 等标签, 也会触发 GET 请求.
后面我们还会学习, 使用 JavaScript 中的 ajax 也能构造 GET 请求

通过Fiddler来观察

GET 请求的特点

  • 首行的第一部分为 GET
  • URL 的 query string 可以为空, 也可以不为空.
  • header 部分有若干个键值对结构.
  • body 部分为空

一个例子

关于 GET 请求的 URL 长度问题
网上有些资料上描述: get请求长度最多1024kb 这样的说法是错误的.
HTTP 协议由 RFC 2616 标准定义, 标准原文中明确说明: “Hypertext Transfer Protocol —
HTTP/1.1,” does not specify any requirement for URL length.
没有对 URL 的长度有任何的限制.
实际 URL 的长度取决于浏览器的实现和 HTTP 服务器端的实现. 在浏览器端, 不同的浏览器最大长
度是不同的, 但是现代浏览器支持的长度一般都很长; 在服务器端, 一般这个长度是可以配置的


POST方法

POST 方法也是一种常见的方法. 多用于提交用户输入的数据给服务器(例如登陆页面).

通过 HTML 中的 form 标签可以构造 POST 请求, 或者使用 JavaScript 的 ajax 也可以构造 POST 请求

通过Fidder来观察POST请求

POST 请求的特点

  • 首行的第一部分为 POST
  • URL 的 query string 一般为空 (也可以不为空)
  • header 部分有若干个键值对结构.
  • body 部分一般不为空. body 内的数据格式通过 header 中的 Content-Type 指定. body 的长度由header 中的 Content-Length 指定.

一个例子

GET和POST的区别

这就引出了一个经典的面试题

谈谈GET和POST的区别。

首先,GET和POST没有本质的区别。因为在我们HTTP方法的使用是一种混乱的状态,HTTP中有那么多方法,但大家写代码基本上就是一股脑GET/POST方法,大家没太按照规则来写。

同理,GET能干的事情、其实POST方法也能干。但是GET和POST,站在细节上是存在区别的。

区别一:

GET 的 body 一般为空, 需要传递的数据通过 query string 传递, POST 的 query string 一般为空, 需要传递的数据通过 body 传递

区别二:

语义不同: GET 一般用于获取数据, POST 一般用于提交数据

(但现在这个区别已经不明显了,GET也可以用于提交数据,POST也可以用于获取数据。)

区别三:

GET请求一般是幂等的,POST请求一般不是幂等的。

幂等:每次我们输入相同的数据,得到的输出结果是确定的(种瓜得瓜,种豆得豆)。

不幂等:每次我们输入相同的数据,得到的输入结果是不确定的——(可能种瓜得瓜、也可能种瓜得豆)

在实际开发中,我们习惯将GET设置为幂等,将POST设置为不幂等。

区别四:

GET可以被缓存、POST不可以被缓存

缓存:就是提前把结果给记住。
如果是幂等,记住结果是很有用的,节省了下次访问的开销。
如果是不幂等的,就不应该去提前记,因为结果是不确定的,下一次访问的开销还是存在的。

注意!能不能缓存 和 幂不幂等,是有关联的。

如果你在设计 GET 的时候,没有把它设计成幂等,那么GET,也是不能缓存的。
POST 也是同理。

一些补充:

关于幂等性: 标准建议 GET 实现为幂等的. 实际开发中 GET 也不必完全遵守这个规则(主流网站都有 “猜你喜欢” 功能, 会根据用户的历史行为实时更新现有的结果.

关于安全性: 有些资料上说 “POST 比 GET 请安全”. 这样的说法是不科学的. 是否安全取决于

前端在传输密码等敏感信息时是否进行加密, 和 GET POST 无关.

关于传输数据量: 有的资料上说 “GET 传输的数据量小, POST 传输数据量大”. 这个也是不科

学的, 标准没有规定 GET 的 URL 的长度, 也没有规定 POST 的 body 的长度. 传输数据量多少,

完全取决于不同浏览器和不同服务器之间的实现区别.

关于传输数据类型: 有的资料上说 “GET 只能传输文本数据, POST 可以传输二进制数据”. 这

个也是不科学的. GET 的 query string 虽然无法直接传输二进制数据, 但是可以针对二进制数

据进行 urlencode


请求报头(header)

HOST

表示服务器主机的地址和端口

Content-Length && ContentType

Content-Length:表示body中的数据长度

Content-Type:表示请求中的body中的数据格式

User-Agent(UA)

UA:用户代理,表示的是,当前用户是在拿一个什么什么样的工具在上网

虽然User-Agent 这一个键值对,我们并不能全部看懂。
但是不妨碍我们得出结论:
我们可以发现:User-Agent,总的来说,分为2部分信息:操作系统 + 浏览器 信息。

为什么要有这样一个信息呢?
其实理由也很简单:
在上古时期,就是在互联网刚开始发展的时候。
那个时候,浏览器处在一个飞速进步的状态。
最开始的浏览器,只能显示文本,【HTML】
再后来,能够显示图片了。【HTML】
再后来,能够显示各种复杂的样式了。【CSS】
再后来,能够加载 js 实现交互了。【JS】
再后来,能够支持各种多媒体了(播放视频什么的…)。

那么,问题就来了:
由于那个时期的浏览器发展很快,所以就导致市场被割裂了。
一部分用户,用的是比较老的浏览器。(只能显示文本)
一部分用户,用的是比较新的浏览器。(能够支持 js)
因此,也就给我们网站开发人员带来了很大的挑战。
在设计一个网页的时候,到底要不要给这个网页加上 JS ,或者CSS。
加了吧,有一些用户的浏览器不支持。
不加吧,有一些用户的体验不好。
【用户表示:我能用,你凭什么不给我用?】
【程序员:我开发的浏览器不支持 JS,岂不是说明我很菜?】

当时,为了解决这个问题,聪明的程序员就想到了一个办法。
让浏览器发送的请求中,包含一个数据:“自爆家门”。
就是你浏览器请求过来了,你先告诉我,你的浏览器大概能支持哪些功能。
或者说,告诉我,你的浏览器处于一个什么版本,是旧的,还是新的。
此时,服务器就可以根据浏览器中这个 “自爆家门” 的信息,就可以做出区分了。
根据你的浏览器版本,或者说根据你的浏览器所支持的功能,来返回一个你的浏览器能够支持的网页数据。
这样做,就可以满足每个用户的不同需求。

这里 User-Agent 键值对,就是在做着这样的一个“自爆家门”的工作。


浏览器发展至今,主流浏览器的功能已经差别很小了。
十年前,浏览器兼容性,还是前端开发要考虑的大问题。
兼容性:如何去兼容老的浏览器
十年后的现在,今天基本上是不用考虑了。
因为大部分用户使用的浏览器,都是比较现代的浏览器。
该有的功能,它都有。
与最新的浏览器,没有太大的区别。
也就需要关注那么问题了。
故:放到现在,UA 这个字段起到的作用就已经不那么大了。
其实,我们不告诉服务器,用的是什么浏览器。
服务器也大概知道,在这个年代,不会存在太老旧的浏览器。
所以,直接把页面发给你,你的浏览器肯定是能处理的。


但是!随着当下移动互联网的到来,UA 现在又有了新的使命。
用来区分是 PC端,还是 手机端。

当前 PC端 和 手机端,最大的区别就是 屏幕尺寸和比例。
手机端的屏幕尺寸,是远远小于 PC端的。
一般手机端的网页,就得把按钮之类的,设计的大点。
要不然,你手指点不到按钮。
屏幕比例 PC都是宽屏,手机都是窄屏,比例的不同就导致页面布局就得不同。

因此,我们的服务器就可以根据 UA 来区分 当前是 手机,还是PC。
如果是手机,就返回一个手机版的网页;如果是PC,就返回一个PC版的网页。
这两个版本的网页,它们的尺寸和布局有着很大的不同。
这样做,不管用户使用何种设备,打开一个网页,都会用的很舒服。

这就是当下 UA 的主要功能。

另外,响应式布局也能做到根据设备窗口的大小,来修改页面的样式。
响应式布局,大概就是根据当前浏览器窗口宽度自动修改样式。
这个操作,更加考验前端工程师的功底。
写一个页面,适用于两种不同的平台,确实可以做到,但是代码就会更加的复杂。
代码一复杂,写代码就容易出错。
可能更多的是,写两个页面,分别对应着 手机 和 PC 端。

User-Agent 之所以是这个样子是因为历史遗留问题. 可以参考
User-Agent 的故事: http://www.nowamagic.net/librarys/veda/detail/2576
————————————————

Referer

表示当前这个页面是从哪个页面跳转过来的

cookie

明确一点:浏览器,为了安全,默认情况下是不能让页面的 js 访问到 用户电脑上的文件系统的。

假设某个网页上,包含恶意代码。
然后,我们不小心点到的,就可能触发这个恶意代码,可能就把你电脑上的资料全给删除了。

显然这是一件非常难受的事情!
所以浏览器为了保护 用户电脑上的 资料,就会禁止页面的 js 访问到文件系统。
就是说,页面的 js 是获取不到:当前用户电脑上的文件有哪些 ,就别提进行删除操作了。
这是浏览器为了安全而引入的机制。

但是!这样的安全限制,也带来了一些麻烦。
因为有时候,我们确实需要让页面这里持久化存储一些数据,方便后续访问网站。
举个例子:
其中,最典型的,就是序要存储 用户当前的身份信息。
————————————————

总结:
Cookie 是浏览器提供的一个持久化存储数据的机制,
Cookie 的最重要的应用场景,就是存储会话ID,进一步的让访问服务器的后续页面的时候,能够带上这个 id 从而让服务器能够知道当前的用户信息。
另外,服务器上保存用户信息这样的机制,就被称为 Session(会话)、

那么,Cookie能不能用存别的信息??
当然也是阔以的!!完全取决你怎么去设计。

大家一定要重点理解 cookie 和 session 的 工作机制。
这件事对于我们后面去实现一些,类似于登录页面,这样的功能,是非常有必要的!
那么,当然了,在讲到后面具体代码的时候,还会通过写代码的形式,让大家进一步的了解cookie 和 session 的工作过程。
当下,咱们就只需要“简单” 的,从理论的角度来认识它的一个工作过程就行了
————————————————

HTTP响应详解

常见的响应码

  • 200 请求成功
  • 302 表示请求重新定向
  • 404 表示请求服务器已经收到,但是你要的数据不存在(请求地址错误)
  • 500 表示服务器已经收到请求,但是服务器内部错误(代码发生错误)

HTTP请求响应过程中的Content-type

请求 和 响应中的 Content-Type ,是不一样的。

请求的Content-Type常见取值

application/x-www-from-urlencoded

以键值对的数据格式提交

响应中的 Content-Type 常见取值有以下几种:

  • text/html : body 数据格式是 HTML
  • text/css : body 数据格式是 CSS
  • application/javascript : body 数据格式是 JavaScript
  • application/json : body 数据格式是 JSON

————————————————

http响应内容类型:Content-Type – 简书