✏️作者:银河罐头
系列专栏:JavaEE
“种一棵树最好的时间是十年前,其次是现在”
HTTP 协议是应用层最广泛使用的协议之一。
浏览器从服务器获取到页面就是基于 http 协议。HTTP 就是 浏览器 和 服务器 之间的交互桥梁。
目前主要使用的是 HTTP1.1
HTTP 往往是基于传输层的 TCP 协议实现的.
浏览器就会根据这个 URL 构造一个 HTTP 请求,发给服务器。服务器就会返回一个 HTTP 响应(包含了 html, css, js, 图片…)
浏览器再把得到的 html 等数据进行显示出来(渲染)
HTTP 协议 全称是超文本传输协议。
http 协议交互的详细过程,可以借助第三方的工具来看到,称为抓包工具。
这里我使用的是 fiddler, 专注 http,使用起来简单。
立即显示出当前电脑上某个程序使用 http 和 服务器交互的过程。
fiddler 本质上是一个代理程序,使用的时候有 2 个注意事项:
代理
代理就是找个人帮你干活。
举个栗子:
我在寝室里,饿了,但是又懒得下楼,我就让我舍友去超市帮我带一个泡面
如果我自己去超市,也能完成这次交易,但是我懒,就让室友跑腿了,室友相当于就是"代理"。室友对于我和超市老板的交易细节是非常清楚的。
代理还分两种,正向代理和反向代理。
正向代理,代表客户端的代理。
反向代理,代表服务器的代理。
https 是基于 http 搞出来的进化版协议。当前互联网上的绝大部分服务器都是支持 https 的。
而 fiddler 不能抓 https 的包,需要我们手动启用一下 https 并且安装证书。
请求是有一定格式的,fiddler 会按照 http 的格式解析请求,呈现出不同的显示效果,此处就看最原始的效果。
任何一个程序都能使用 http 协议,不仅仅是 浏览器。
HTTP请求:
通过抓包结果,可以看到当前 http 请求,其实是个行文本格式的数据。相比于 tcp 这样的二进制数据,更方便用户进行观察。
压缩是什么原理?
为了表达一个信息,重新进行编码。表达的含义是一样的,重新编码之后,体积就能减小。
HTTP响应:
这个文本数据,就是搜狗首页,html 里的内容。
GET https://www.sogou.com/ HTTP/1.1
首行。
包含 3 个部分,之间用空格来区分。
GET : HTTP 的方法(method)
https://www.sogou.com/
URL 俗称的网址。
URL, 唯一资源定位符,标识互联网上唯一资源的位置。(资源在哪,在哪个服务器的哪个目录下的哪个文件)
URI,唯一资源标识符,身份标识,为了和别的资源区分开。
HTTP/1.1 : 版本号
URL 的详细规则由 因特网标准RFC1738 进行了约定.
tcp, ip, udp 协议格式都是由 rfc 文档定义的。
url 不是 http 专属的,很多协议都可以使用 url。
url 最关键的 4 个 部分:
1.域名
2.端口号
3.带层次的文件路径
4.查询字符串
一个 url,有些部分是可以省略的。
一个 HTTP 服务器提供的资源是很多的,不同的路径拿到的资源是不同的。
url 有些字符是由特定含义的,就需要对内容进行重新编码,如果不编码直接写中文,可能浏览器就无法正确识别了。
urlencode 编码
urldecode 解码
HTTP 协议是一个 行文本协议。
方法描述了此次请求的语义。
其中最常见的就是 get , post
1.在浏览器地址栏直接输入 url
2.html 里的 link, script, img, a…
3.通过 js 构造 GET 请求
通过 fiddler 抓包一个 GET 请求:
登录,上传文件
比如我 登录 gitee,
用 fiddler 抓包一个 POST请求
HTTP 请求可以分成 4 个部分:
1.首行
2.请求头(header)
3.空行
4.正文(body)
body 里放的是 程序员自定义的信息。
经典面试题
首先要明确的是,GET 和 POST 没有本质区别,只是在使用习惯上有差异(大部分场景下,彼此之间都能相互替代).
区别:
1.如果是 GET 请求,一般没有 body;POST 请求一般有 body.
2.GET 可以给 服务器传递一些信息,GET 传递的信息一般放在 query string 里面。POST 传递信息则通过 body。
3.GET 请求一般是用于从服务器获取数据;POST 一般是用于给服务器提交数据。
4.GET 通常会被设计成幂等的,POST 不要求幂等。
幂等,指的是相同的输入,得到的结果是确定的。
5.GET 可以被缓存,POST 一般不能被缓存。(把请求的结果保存下来了,下次再请求时就不用真请求,直接取缓存的结果)
每一行是一个键值对,键和值之间用 :分割。
大概描述了服务器所在的地址和端口。Host 这里的地址和端口,用来描述你最终要访问的目标。这个内容大概率和 url 中是一样的,也有一定情况是不同的。
如果是 GET 请求,没有 body, 就没有Content-Length 和 Content-Type 这俩字段;如果是 POST 请求,有 body ,就有这俩字段。
Content-Type 取值是非常多的。
text/html
text/css
image/png
image/jpg
application/javascript
application/json
描述了浏览器和操作系统的版本。
最早期的浏览器只支持文本,后来浏览器支持图片,再后来支持视频、音频、js…
浏览器开发者针对不同阶段的浏览器做了不同的版本,通过判定请求的User-Agent
现在的 User-Agent 主要用来区分 PC 和移动端
当前页面的"来源"
如果直接通过地址栏输入地址或者直接点击 收藏夹,都是没有 referer 的。
广告商在很多平台上都投放了广告。广告是按照点击计费的,用户点击广告,此时就会跳转到广告主所在的页面上,同时广告商就要给广告平台发钱。
广告被点击了多少次,次数如何衡量?如何统计?
平台可以统计,广告商自己也能统计。
平台这边有个计费服务器,每次点击都打到计费服务器上,记录日志。
广告商也有日志,广告商投放广告可能投放了很多平台,记录有哪些是百度的 referer,哪些是360的 referer,哪些是搜狗的 referer…
HTTP 本身是明文传输的,很容易获取到请求内容,也有办法篡改内容。
有可能本来是来自搜狗的请求,referer 被改成是别人的?
“运营商劫持”(非正常情况)
本质上是浏览器给网页本地存储数据的机制。
网页,默认是不允许访问计算机的硬盘的(保证安全)。
cookie, 浏览器对于访问硬盘做出了明确的限制。
cookie, 是通过键值对的方式存储数据的。
Cookie 的数据是来自于服务器的,服务器会通过 http 响应的报头部分(Set-Cookie 字段)
服务器来决定 浏览器的 Cookie 要存什么。
可以认为是存在浏览器中的,本质上是存在硬盘的。
不同的浏览器,各自存各自的 Cookie。同一个浏览器不同的域名,对应不同的 Cookie。
Cookie 里的内容不光是键值对,还有过期时间。比如有些网站,登陆一次后,自动记录登录状态。
回到服务器。
客户端通过 Cookie 记录当前用户使用中间状态,当用户访问浏览器的时候,就自动把 Cookie 内容带到请求里,服务器就能知道现在客户端是啥样子的。
举个栗子:
我想配个电脑(台式机),在淘宝上和客服反复拉扯。
1.先跟客服说我的需求,客服说 ok,然后 客服没动静了
2.过了一会儿,我又发消息说你在吗。
(客服同一时间是要和很多人服务的,客服看到后第一反应是先往上翻一翻聊天记录,看看我找他是要干啥,这个聊天记录就相当于 cookie,表示客户端当前的状态)
Cookie 就好像是 服务器在浏览器这边搞的一个寄存处一样。
Cookie 可能是用来保存登录状态的,也可能用来存别的。浏览器保存账号密码是别的功能,和 http 关联不大。
有些公共电脑(比如打印店的电脑),登录自己的账号,此时登录状态就保存在 Cookie 中了,下次使用的时候 很可能 Cookie 就过期了,就要重新登录了。
正文中的内容格式和 header 中的 Content-Type 密切相关.
1.application/x-www-form-urlencoded
2.multipart/form-data
3.application/json
四个部分
1.首行
2.header
3.空行
表示 header 的结束标记
4.body
描述了这次响应 的结果(成功?失败?原因是啥?)
200 OK 成功了
404 Not Found 要访问的资源不存在,在服务器上没找着。
403 Forbidden 访问被拒绝,没有权限访问
302 Move temporarily 重定向 (类似于呼叫转移)
这样的响应报文中,会在 header 中有个 Location 属性,通过这个属性描述要跳转到哪个新的网址。
500 服务器内部错误(服务器代码抛异常)
504 Gateway Timeout(响应时间太久,浏览器等不及了)
gateway 网关,一个网络的入口/出口,通常也代指一个机房的入口服务器。
状态码分成几个大类:
HTTP 协议中有些是可以自定义的:
1.URL 中的路径
2.URL 中的 query string
3.header 中的键值对
4.header 中 cookie 键值对
5.body
对于 GET 请求:
1.地址栏直接输入
2.点击收藏夹
3.html 中的 link, script, img, a…
4.form 标签(通过代码构造)
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<form action="https://www.sogou.com" method="post">
<input type="text" name="studentName">
<input type="submit" value="提交">
form>
body>
html>
对于 form 构造的 POST 请求来说,body 里的数据格式和 query string 是非常相似的,也是键值对结构,键值对之间用 & 分割,键和值之间用 = 分割。
form 标签只能构造 GET 和 POST 请求,无法构造 PUT, DELETE, OPTIONS 等方法的请求。
另外还有一种,功能更强的构造 http 请求的方式,ajax.
Ajax 即Asynchronous Javascript And XML(异步 JavaScript 和 XML).
ajax, 也是浏览器提供的一种,通过 js 构造 http 请求的方式。
同步:A 始终盯着 B,A 负责关注B 啥时候就绪
异步:A 不盯着 B,B 就绪之后主动通知 A
html 中,通过 ajax 发起 http 请求,就属于"异步"的方式。
这一行代码执行"发送请求"操作之后,不必等待服务器响应回来,就可以立即先往下执行。当服务器的响应回来之后,再由浏览器通知到我们代码当中。
$.ajax();
//只有一个参数,是一个 js 对象(大括号表示的键值对)
jquery 中,$ 是一个特殊的全局变量,jquery 的 api 都是以 $ 的方法的形式引出来的。
<script>
$.ajax({
type:'get',
url:'https://www.sogou.com?studentName=zhangsan',
//此处 success 就声明了一个回调函数,就会在服务器响应回到浏览器的时候触发该回调
//正是此处的回调,体现了"异步"
success:function(data) {
//data 则是响应的正文部分
console.log("服务器响应回到浏览器之后, 浏览器触发该回调, 通知到我们的代码当中");
}
});
console.log("浏览器继续往下执行后续代码");
</script>
注意 : 该代码直接执行,只是能看到构造的请求,不能获取到正确的响应。因为发送请求给搜狗这个服务器,服务器没有处理请求。
后面我们自己能写服务器了之后,就可以给自己的服务器发送请求,自然就可以处理了。
js 本身是不能直接控制操作系统的线程(不像 Java),但是浏览器在 实现 ajax 的时候在内部使用了多线程。js 直观上看没有多线程,实际上还是涉及到的。
ajax 和 form 相比:ajax 功能更强
1.支持 put, delete 等方法,而 form 只有 get , post
2.ajax 发送的 请求可以灵活设置 header
3.ajax 发送的请求的 body 也是可以灵活设置的。
测试免不了要构造 http 请求,写代码构造吗?
还有更为方便的构造 http 请求的方式,使用第三方工具 postman
postman 是个有对象的软件,postwoman(功能和 postman差不多)
1.先注册登录
2.创建 workplace
3.新建一个标签页
除了上面的手动构造之外,postman 还有一个功能,可以生成构造请求的代码,方便我们在自己的程序中集成。
抢票相当于 是 线程竞争信号量