目录
🐲10.1 通过form表单发送GET请求 和 POST请求
HTTP协议,前后端交互的桥梁
Tomcat java中最主流的HTTP服务器之一,写后端的代码,很多都是基于Tomcat的二次开发
Servlet Tomcat给后端程序员提供的开发服务器程序的API合集
Linux 使用云服务器来部署写好的程序
🦄1. 了解HTTP
在网络技术中,最核心的概念就是"协议"
在应用层中,有很多协议,而HTTP就是应用层典型的协议,
应用层很多时候需要程序员自定义应用层协议,也有一些现成的协议来让我们使用
而HTTP就是其中最常使用的
(1)浏览器和服务器的交互(打开网页),大可能性是HTTP协议
(2)手机APP和服务器之间的交互,也大可能性是HTTP协议
目前HTTP版本最新是3.0了,但最常见的还是HTTP 1.1版本
🟧比如说在浏览器中打开一个网址,这个过程就是通过HTTP和服务器进行了通信
HTTP这个协议,是属于最典型的"一问一答"模型的协议
学习HTTP协议,最关键的就是HTTP报文格式
报文格式就描述了HTTP请求是啥样的,响应是啥样的
这就需要使用"抓包工具"来捕获请求交互的详细情况
🦄2. 抓包
抓包工具,是个特殊的软件,相当于一个"代理程序",浏览器给服务器发的请求就会经过这个代理程序,进一步的就能分析出请求和响应的结果如何
正向代理(给客户端提供服务的,和客户端关系紧密)站在服务器的角度,
正向代理把真实的客户端给隐藏起来了,服务器不知道真实的客户端是啥
反向代理(给服务器提供服务器的,和服务器关系紧密)
站在客户端的角度,反向代理把真实的服务器给隐藏起来了,客户端不知道真实的服务器是啥
使用抓包工具,来分析HTTP协议的工作过程(抓包工具很多,这里使用fiddler)
Fiddler | Web Debugging Proxy and Troubleshooting Solutions (telerik.com)
也可以直接点这个链接下载
链接:https://pan.baidu.com/s/1Ay95pOUzKDyCDE1OOa0u7w?pwd=xemc
提取码:xemc
需要注意的是,现在单纯的HTTP很少了,更多的是HTTPS
HTTPS可以理解为升级版本的HTTP,也就是在HTTP的基础上,加了个加密层
所以,这个要是直接抓的,不一定能抓取到多个请求
这就需要开启fiddler,抓取HTTPS的功能
如果开启了上面HTTPS也安装了根证书,还是抓不到,
就要检查是否你的电脑上安装了其他的代理程序/代理作用的浏览器插件
(这里的代理程序/代理作用比如:fq工具/游戏加速器/steam++,本质上都是代理,这些程序都会和fiddler发生冲突,就是不可以同时运行.所以使用fiddler时就要把其他的代理程序关闭/禁用)
🟥下面来看一下fiddler的各区域的作用
🦄3. http协议格式
🟧 http协议请求,可以点击view in Notepad,用记事本打开
🐲3.1 完整的HTTP请求格式
构造一个HTTP请求,本质上就是往一个TCP socket中,按照下列格式来写入数据即可
小技巧:清空fiddler中已经抓到的报文
先选中一个ctrl+a选中所有,然后delete清空所有
🐲3.2 完整的HTTP响应的格式
HTTP请求
🦄4. 认识URL
URL唯一资源定位符 (用这个来找到网络上的资源)
URI 唯一资源标识符 (用这个来区分一个网络上的资源)
URL里面是啥样子,是有"RFC标准文档"来进行描述的
RFC标准文档,描述了很多,网络中的协议标准包括IP TCP UDP HTTP ....
(1) 协议方案名:URL并非是HTTP独有的,是给很多协议都能使用的,比如jdbc:mysql://
(2) 登录信息:现在这种写法基本上没了,都是单独写一个登录页面,在输入框进行输入
(3) 服务器地址: 也就是服务器的IP地址,也可以是域名(域名和IP效果一样,DNS域名解析系统,能够帮我们自动的把域名转换为IP地址)
(4) 服务器端口号: 标识了要访问目标服务器的哪个进程(将进程和端口号进行绑定,在浏览器中的URL里面端口号经常会省略不写,省略的时候使用的是当前协议的默认端口)
(5) 带层次的文件路径: 服务器进程可能会提供出很多的资源(比如一些html文件或者css文件,图片),这些资源 又会放到一些具体的目录中(在URL中写的路径,不一定就真的对应到服务器上的某个硬盘上的目录,服务器上提供的资源,可能是一个真实存在的文件,也可能是一个"虚拟出来的文件")
访问静态资源:硬盘上真实存在的资源
访问动态资源:在应用程序代码中,根据请求构造出来的一个html片段,这种并不是硬盘上真实存在的文件,但是也可以是一个标准的html
(6) 查询字符串: ?后面的也是 键值对 结构.称为查询字符串,相当于浏览器给服务器传递的一些必要的参数(URL中,查询字符串,键值对完全是自定义的)
(7) 片段标识符: 用来区分一个网页中的哪个部分,可以借助于片段标识符快速跳转到网页的某个部分
把原始的字符(按字节为单位转义),转成转义符(比如汉字) -----> URL encode(编码)
把转义后的字符还原成原始的字符 ----> URL decode(解码)
🦄5. http中的"方法"
这里的"方法"可以理解为 你这个请求想干啥
方法 | 说明 | 支持的HTTP协议版本 |
---|---|---|
get | 获取资源 | 1.0 1.1 |
post | 传输实体主体 | 1.0 1.1 |
put | 传输文件 | 1.0 1.1 |
head | 获得报文首部 | 1.0 1.1 |
delete | 删除文件 | 1.0 1.1 |
options | 询问支持的方法 | 1.1 |
trace | 追踪路径 | 1.1 |
connect | 要求用隧道协议连接代理 | 1.1 |
link | 建立和资源之间的联系 | 1.0 |
unlink | 断开连接关系 | 1.0 |
🐲5.1 get 是最常用的HTTP请求方法
(1) 浏览器地址栏直接输入URL, 此时就会触发get
(2) html 里面的 link, a, img, script也会触发get请求(href/src 都会引用一个外部的资源,本质上就是浏览器会重新发送一个get请求,来从服务器拿到对应的数据)
(3) form表单 html里的form标签,可以构造出get请求
(4) ajax
get请求的特点:
(1) 首行第一部分为get
(2) URL的 query string 可以为空,也可以不为空(如果需要给服务器传递一些参数,这些参数通常就是通过 querystring 来传过去的)
(3) header 部分有若干个键值对结构
(4) body 部分为空
🐲5.2. post 产生的途径
(1) form
(2) ajax
post请求的特点
(1) 方法叫做post
(2) URL通常是没有 query string 的
(3) 也是有若干header,键值对的形式
(4) body这里通常是有的,post在传递信息给服务器的时候,通常就会把信息放到body中
面试题: get 和 post 的区别
首先明确, get 和 post 没有本质上的区别 这个"没有本质上的区别"是指, 使用 get 实现的场景, 基本都可以使用 post 来代替 使用 post 实现的场景, 也可以用 get 来代替 其次,再来看 细节上的区别1) get 的语义, 是 "从服务器获取数据", post 的语义, 是 "往服务器上提交数据" (虽说http当时设计是这样来规定的,但是实际中,程序员并没有遵守这个,因为它那个设计是建议你采取这样的语义,并不是说必须) 2) 使用习惯上, 给服务器传递的消息,get通常是放在 url 的 query string 中post 通常是放在 body中 (但是get也是可以把数据放在body中的,只不过很少见 ; post也是可以把数据放在 query string中的,也很少见) 3) get 请求建议实现成 "幂等" 的, post 一般则不要求实现成 "幂等" (幂等: 输入确定,输出结果也就是确定的) 比如 设计服务器的时候,就需要提供一些 "接口/api" api 传入的参数,就视为是输入 api 返回的结果,就视为是输出 基于get 的 api 一般会建议设计成幂等的 基于post 的api 则无要求 4) 在幂等的基础上, get 的请求结果是可以被缓存的(浏览器默认的行为), post 则一般不会缓存 如果当前 get 确实是幂等的,就不必处理,就让浏览器缓存,没问题 如果当前 get 不是幂等的,就需要提供特殊技巧避免浏览器产生缓存(典型的技巧是,让每次get请求的url都不相同,通过特殊的 query string 来保证 url不同)
"post" 和 "get" 安全性问题
有一种说法是,get把参数放到url中,如果实现登录页面,点击登录后,你的用户名和密码就直接以query string 的形式放到url中了,就直接显示到浏览器地址栏中了,会被别人看到,所以就不安全
而post是把参数放到body中,body不会显示到浏览器界面上,所以就不会直接显示出来就更安全
需要注意的是,虽然把用户名和密码放到url中不好,但是放到post的body中也并没有说更加的安全,
不能说 "不在用户界面上显示" 就是安全(比如说我如果这里拿抓包工具也可以查看到用户名和密码,所以这种安全也太没价值了吧)
安全,应该就是比如数据被人截获后,不会对你的数据造成泄露这样的影响,所以只要没给代码进行加密,就根本谈不上"安全"
http是没有加密功能的,而https是有一定的加密功能的,
但相对来说实际中,主要还是通过业务上的代码来实现加密
🦄6. 请求报头header
header也是"键值对"的结构,这里都是标准规定的,有特定含义的,也可以放一些自定义的键值对
🐲6.1 Host:表示服务器主机的地址和接口
Host:gia.jd.com 放的就是ip+端口
这里的端口可以省略,省略则表示默认值
HTTP的默认值是80 HTTPS的默认值是443
可以看到URL里面也有这个服务器主机的IP和端口,那为啥还要搞一个Host
这是因为,实际上URL中的IP和端口,和Host中的IP和端口不一定完全一样
(当请求经过代理来访问的时候,是可能会不一样的)
🐲6.2 Content-Length
Content-Length(表示body中的数据长度)
Content-Length Content-Type 这两个字段,不一定有,但如果有肯定是同时出现的
如果请求没有body(GET) 就没有这两个字段
如果请有body(POST)一定有这两个字段
HTTP协议,在传输层是基于TCP(至少在HTTP3.0 之前是这样的,在3.0就变为了UDP)
TCP是面向字节流的,这就会有粘包问题(关于这个可以看我这篇博客http://t.csdn.cn/buEsA)
当时是这样解释的
而TCP接收缓冲区是这样的
所以这就需要Content-Length来表示body中的数据长度,来解决粘包问题
Content-Length不需要我们自己手动设置,一般都是浏览器和HTTP服务器自己计算好的
🐲6.3 Content-Type
Content-Type(表示请求的body中的数据格式)
Content-Type:body中的数据可以存放很多种格式,而这对于接收方来说,解析方式是截然不同的
常见选项
(1) application/x-www-form-urlencoded: form表单构造的请求,就是这个Content-Type
body的格式
title=test&content=hello
这个格式就是和query string是一样的,里面可以放多个键值对,键值对之间使用&来分割
键和值之间使用 = 来分割(并且这里也是需要 urlencode的)
(2) multipart/form-data:这个格式主要是在上传文件的时候会出现
Content-Type:multipart/form-data; boundary=---- WebKitFormBoundaryrGKCBY7qhFd3TrwA ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="text" title ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="file"; filename="chrome.png" Content-Type: image/png PNG ... content of chrome.png ... ------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
(3) application/json 数据为json格式
body格式比如:
{"username":"123456789","password":"xxxx","code":"jw7l","uuid":"d110a05ccde64b16 a861fa2bddfdcd15"}
🐲6.4 User-Agent(UA)
UA主要包含的信息,就是 操作系统信息 和 浏览器信息
描述了用户在使用啥样的设备来上网
以前的浏览器,是支持文字,--> 开始支持图片 ---> 能够支持 js ---> 能够支持音频视频
浏览器就是这样慢慢来发展的
这样的情况,就会导致同一个时间段内,可以存在好多种浏览器
此时就会有一些问题
1,实现一个纯文字的页面,可以让所以人都能打开,但这也太老了
2.实现一个支持音频视频+js的网站,就会让一些浏览器打不开
所以为了解决这个问题就可以,
通过UA来收集到浏览器/操作系统的信息,进一步的就知道浏览器/系统支持啥样的页面
如果是一个比较老的浏览器,那就返回一个老的页面
如果是一个比较新版本的浏览器,那就返回一个功能更丰富的页面
而慢慢发展到今天,浏览器基本上都一样了,开发人员也就不用考虑这么多版本兼容问题了
UA这块的作用可以说是结束了
但UA还有其他的作用
现在存在的几种主流上网设备, PC,平板,手机,屏幕的大小都是不同的,打开浏览器页面的大小也是不同的
所以这个时候UA就可以,来识别出PC/手机/平板(来开发出不同版本的页面了)
这里就有个技术叫"响应式页面" 通过特殊的CSS和JS,来感知当前浏览器窗口的尺寸,根据不同的尺寸来进行重新页面布局排列,这样一个页面就可以兼容多个设备了
🐲6.5 Referer
表示这个页面是从哪个页面跳转过来的,所以可能会有的没有,有的有如果直接在浏览器中输入URL, 或者直接通过收藏夹访问页面时是没有 Referer 的.
🐲6.6 Cookie
也是请求头中的一个重要字段,是浏览器在本地存储数据(存到硬盘上)的一种机制
为了解决这个问题,浏览器就专门提供了特殊的API来给网页使用,可以让网页存储一些简单的数据
浏览器提供的持久化存储方法有好几种
Cookie 是最经典的一种方案(最老)
LocalStorage是一种比较新的方案
indexDB是更新的方法
1. cookie 不是缓存(缓存中的数据不一定持久化,也可以在内存里缓存,缓存中的数据时用来"提高访问速度的"),
是持久化存储数据(保存在硬盘)的手段
2. cookie 和 get 没直接关系,其他的post, put ...的也都有 cookie
3. cookie 这里的键值对 都是简单的字符串
使用 cookie 作为保存数据的手段,只能存一些简单的键值对信息,简单的字符串
如果想让cookie存图片/视频/flash...它是做不到的
比如,可以使用 cookie 存(具体存什么,程序员自定义)
(1) 上次访问页面的时间
(2) 当前网页的访问次数
(3) 当前访问页面的身份信息(身份标识, id)
1. cookie从哪里来
cookie是存在浏览器的,来源是服务器
像这里的这些 cookie都是浏览器访问了 服务器之后,由服务器返回的
在服务器返回的响应报文中,可以在响应 header 中包含一个/多个 Set-Cookie (键值对)这样的资源(程序员在服务器代码中构造出来的)
浏览器看到 Set-Cookie 就会把这样的数据给保存在浏览器本地
2. cookie到哪里去
来自于服务器,存储于浏览器,
当浏览器保存了 cookie 之后,下次浏览器访问同一个网站,就会把之前本地存储的 cookie 再通过 http请求 header 中的 cookie 给带过去
为啥数据要这样转一圈
服务器要服务的客户端是很多的,这些不同的客户端应该要有不同的数据
cookie 最典型的应用
最常用的场景就是在客户端维持登录状态
在某个网站上登录成功之后,浏览器就会记住当前登录用户的身份信息
然后接下来访问该网站的其他页面,服务器也能知道现在是谁在登录
下面来看一下,这个过程
很多网站都是上面这一套步骤来实现的(主流方式)
但现在一些比较新的网站,就不这样用cookie来进行本地存储了
而是使用 localStorage 之类的方法来保存
🦄7. 认识请求正文body
正文中的内容格式和header中的Content-Type密切相关 有三种常见的情况1) application/x-www-form-urlencoded
2) multipart/form-data
3) application/json
HTTP响应
🦄8. 状态码(status code)
状态码是一个数字,这个数字描述了当前这次请求的 "状态"(成功/失败/其他一些状态)
HTTP状态码大全(常见 HTTP Status Code 含义查询) - 桔子SEO (juziseo.com)
这里介绍几种常见的状态码
(1) 200 表示访问成功(平时正常打开网站,都是这个状态)
打开Fiddler可以看到这一列的状态都是200
(2)404 Not found(后面学习后端开发,会经常见到这个错误)
请求的内容未找到或已删除(就是请求路径写错了)
请求里 -> url -> 路径(表示你要访问的服务器上的资源)
如果你想访问的资源,服务器上没有,此时就会返回404
可以看到我这里再bing.com中随便进一个页面,找不到就会给我返回一个404的状态
还有一种情况是这样的,比如我在B站上随便输入一个页面,找不到就会返回一个404页面
但是这个404的相当于一个有"皮肤"的404 (打开Fiddler可以看到还是404的页面)
(3) 403 Forbidden 访问被拒绝(没有权限)
404和403 本质上都是客户端这里出了问题,
4XX都是客户端出现错误状态
(4) 500 Internal Server Error 服务器内部错误
服务器代码执行过中,出现异常了
(5) 504 Gateway Timeout 访问超时了
一般就是服务器请求量很大的时候,对于服务器的负荷就比较重,导致一些请求来不及响应就会超时5
5XX是服务器错误信息状态
(6) 302 重定向
访问一个旧的URL 自动转移到新的URL上,这个很常见
a. 服务器的地址迁移 (比如一个服务器的域名更换了,防止有人还访问旧的域名,那么此时给这个搞一个重定向,就可以在访问旧域名时,自动进行跳转到新的域名,来进行一个过渡)
b. 搜索引擎点击跳转
🦄9. 响应报头header和响应正文body
响应报头的基本格式和请求报头格式基本一致
类似于 Content-Type , Content-Length 等属性的含义也和请求中的含义一致
Content-Type
text/html : body 数据格式是 HTML text/css : body 数据格式是 CSS application/javascript : body 数据格式是 JavaScript application/json : body 数据格式是 JSON正文的具体格式取决于 Content-Type
🦄10. 构造http请求
🐲10.1 通过form表单发送GET请求 和 POST请求
如何构造http请求,浏览器自己构造的(地址栏中写url,构造出get请求,点击a标签,也会构造get请求img,link,script,也会构造get请求)
form (表单) 是 HTML 中的一个常用标签. 也可以用于给服务器发送 GET 或者 POST 请求
form最关键的作用,就是给服务器传键值对
get是直接在url中可以看到, post可以在body中看到
此时这个键值对就出现在了URL中
借助这些标签来给请求构造数据,键值对结构的数据
每个input就对应一个键值对,input的name属性就是 "键",input里用户输入的内容就是"值"
如果方法是get,那么键值对就会出现在url的query string中
如果方法是post,那么键值对就会放到body中
如果此时把method修改为post
可以看到提交后,键值对信息并没有出现在URL中
使用Fiddler抓这个包,可以看到在body中
同步异步的理解(*)
之前学习java多线程时,加锁时的关键字synchronized 这个意思是同步的
而现在学习ajax它的全称是 Asynchronous Javascript
asynchronized异步的(给同步的前面加个a)
同步这个词有多种含义(彼此之间没有联系)
在多线程中的同步,指的就是"互斥"
在网络通信/IO操作的时候,也涉及到同步
表示的含义是,谁发起的请求,谁负责接收结果
(去饭店吃饭,我点的单,我自己取餐端走)
而异步是和上面的同步相对的
表示的是,发起请求的主体,不负责接收结果,而是由别人主动推送过来(ajax就是这个)
(去饭店吃饭,我点的单,服务员把餐取走)
🐲10.2 通过ajax构造http请求
form只能构造post和get请求,而ajax比form更好,可以各种http方法都能构造
ajax还有一个特点是
form 构造的http请求,一定会触发页面跳转
ajax 默认发起的请求不会引起跳转,也可以手动控制跳转
使用ajax不去触发跳转,就可以达到"局部刷新"的效果(这个大大提高了页面的加载效率)
在代码中使用ajax构造http请求
ajax api 是属于浏览器元素自带的,但原生的api不太好用
所以,可以使用第三方库,封装好的api,来代替原生的api
ajax构造http请求,使用第三方库jquery,可以直接通过网络地址,把jquery引入到代码中
(搜索 jquery cdn)
需要明白的是,不论哪个编程语言,只要可以操作网络(能够进行socket编程)就一定可以构造http请求(往一个tcp socket 里写一个符合http协议格式的字符串)
🐲10.3 通过postman构造http请求
postman就属于一个专门用来构造HTTP请求的第三方工具,主要用来帮助我们进行 接口测试
接口测试:后端写好了服务器之后,需要提供一些HTTP的接口(可以接收一些HTTP请求,返回不同的响应),程序员就要验证下接口对不对,就可以使用前面说的这些办法来发(浏览器地址栏,a标签,form,ajax)
这里就有一个专门用来构造HTTP请求的工具(postman),更方便的来构造http请求了
postwoman:也是用来构造http请求