目录
简介
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 是一个文本格式的协议. 可以通过 Chrome 开发者工具或者 Fiddler 抓包, 分析 HTTP 请求/响应的细节
思考问题: 为什么 HTTP 报文中要存在 "空行"?
因为 HTTP 协议并没有规定报头部分的键值对有多少个. 空行就相当于是 "报头的结束标记", 或者是 "报头和正文之间的分隔符".HTTP 在传输层依赖 TCP 协议, TCP 是面向字节流的. 如果没有这个空行, 就会出现 "粘包问题"
请求行中的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 来说,它里面的结构看起来比较复杂,其实最重要的,和开发最关系紧密的,主要就是四个部分:
这四个最好掌握!!!!
尤其是 3 和 4 ,和我们写代码是密切相关的!
————————————————
当query string 中如果包含了特殊字符,就需要对特殊字符进行转义。
这个转义的过程,就叫做 URLencode,反之,把转义后的内容还原回来,就叫做URLdecode。
那么为什么需要进行 encode?
其实很好理解,前面也看到了,一个 URL 里面是有很多特殊的含义的符号的。
比如:
/ : ? & = …这些符号都是在 URL中具有特定含义的。
万一,queryString 里面也包含这类特殊符号,就可能导致 URL 被解析失败!
比如:我们刚才说的 ?号,是用来分割 路径 和 查询字符串。
如果前面 和 后面都存在 问号,那完蛋。
服务器收到这条请求,就懵逼了,到底那个问号后是 查询字符串?它就会产生误会。
为了消除歧义,就规定了,一旦 queryString中遇到了这些符号,就将其转义
————————————————
前面讲 HTTP 请求部分的时候,就涉及到:GET 和 POST。
get:就是 得到 / 获得 一个东西。
POST:就是 向服务器 传递 / 发送 一个东西。
HTTP 协议的方法非常多!
但是,最最最常用的,也就是 GET 和 POST。
GET方法
GET 是最常用的 HTTP 方法. 常用于获取服务器上的某个资源.
在浏览器中直接输入 URL, 此时浏览器就会发送出一个 GET 请求.
另外, HTML 中的 link, img, script 等标签, 也会触发 GET 请求.
后面我们还会学习, 使用 JavaScript 中的 ajax 也能构造 GET 请求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没有本质的区别。因为在我们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
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 的工作过程。
当下,咱们就只需要“简单” 的,从理论的角度来认识它的一个工作过程就行了
————————————————
常见的响应码
请求 和 响应中的 Content-Type ,是不一样的。
请求的Content-Type常见取值
application/x-www-from-urlencoded
以键值对的数据格式提交
响应中的 Content-Type 常见取值有以下几种:
————————————————
http响应内容类型:Content-Type - 简书