【HTTP详解】

HTTP协议

1.什么是HTTP

HTTP全称为超文本传输协议,是一种应用非常广泛的应用层协议

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

在这里插入图片描述

HTTP往往是基于传输层的TCP协议实现的,例如HTTP1.0,HTTP1.1,HTTP2.0 ,HTTP3.0基于UDP实现

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

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

如何理解应用层协议

应用层协议关心数据具体内容,为了解决实际问题(编程),包括协议请求要传输哪些信息,信息按照什么样的格式传输,服务器返回的响应要包含哪些信息,信息按照什么样的格式传输,这些是应用层协议需要关心的事情,不需要关心数据怎么传输,传输层,网络层,数据链路层,物理层,这下四层只关心数据的传输,而不关心数据是什么,HTTP就是现成的应用层协议,它已经规定好HTTP请求(响应)包含哪些信息,格式是什么,

HTTP协议的工作过程

网络通信中涉及到客户端和服务器,请求和响应

客户端和服务器之间的沟通存在多种模型

1、一发一收

客户端发送一个请求,服务器返回一个响应,请求和响应是一一对应的。 HTTP协议就是一发一收模型

当我们在浏览器中输入一个"网址",此时浏览器就会给对应的服务器发送一个HTTP请求,对方服务器接收到这个请求之后,经过计算处理,就会返回一个HTTP响应

2、多发一收

客户端发送多个请求,服务器返回一个响应,多个请求对应一个响应,例如:上传大文件。会将大文件分成几个部分,包装成多个请求,进行上传,上传完毕后服务器返回一个响应,上传完毕

3、一发多收

客户端发送一个请求,服务器返回多个响应,一个请求对应多个响应。例如:看直播,看开一个直播间就是发送一个看直播的请求,服务器就会返回直播的内容,就是多个响应

4、多发多收

客户端发送多个请求,服务器返回多个响应。多个请求对应多个响应

2. HTTP协议格式

使用Fiddler抓包工具(只抓HTTP协议的抓包工具),来分析HTTP请求和响应

例如打开CSDN网页

在这里插入图片描述

  • 左侧窗口显示了所有的HTTP请求/响应,可以选中某个请求查看详情,此时选择的是左侧一个蓝色的HTTP请求,并且它的body值最大,这条HTTP请求,就是获取CSDN网页的请求,
  • 右侧上方有个inspectors标签,点击这个分析器标签,就可以打开这个HTTP的请求和响应的格式
  • 右上方窗口显示了HTTP请求的报文内容,切换到Raw标签页可以看到详细的数据格式
  • 右下方窗口显示了HTTP响应的报文内容,切换到Raw标签页可以看到详细的数据格式

可以看到获取CSDN网页的请求类型是HTTPS,HTTPS也是基于HTTP的一种应用层协议,只是在HTTP基础上进行了加密,Fiddler会自动进行解密,还原成初始的HTTP

2.1 抓包工具的原理

Fiddler相当于一个"代理"

当浏览器访问csdn.net时,就会把HTTP请求先发给Fiddler,然后Fiddler将请求发送给CSDN服务器,CSDN服务器处理请求返回响应时,会将响应发送给Fiddler,Fiddler再将响应发给浏览器,因此Fiddler对于浏览器和CSDN服务器之间的交互细节非常清楚

在这里插入图片描述

2.2 抓包结果

HTTP请求

在这里插入图片描述

  • 第一行红色框标注的是首行,首行包括方法,URL,版本号 这三个之间用空格隔开
  • 绿色框标注的是请求头(Header),包含了一些属性,每个属性都是一个键值对,键与值之间使用冒号加空格分割,键值对之间使用换行分割,
  • 蓝色标注框,是一个空行,这个空行用来标注请求头部分结束
  • 光标处在最后一行的红色标注,是body,也就是请求内容,body可以为空,如果body存在,那么请求头中就会有Content-Length属性来标识body的长度,Content-type属性标识body的类型

HTTP响应

在这里插入图片描述

响应和请求的格式类似

  • 首行包括版本号,状态码,状态码的描述,三者用空格分割
  • 绿色标注框表示响应头(Header),其中的属性都是键值对,键与值用冒号加空格分割,键值对之间用换行分割
  • Header下面有一个空行,空行用来表示Header部分结束,
  • 红色标注框表示响应的内容(body),这个HTTP请求是获取CSDN网页,所以响应的内容可以看到是HTML页面,而且我们可以从Header的属性中看到Content-Length来标识body的长度,Content-type标识body的类型

2.3 协议格式小结

在这里插入图片描述

HTTP报文中为什么要存在"空行"

因为HTTP协议并没有规定报头部分的键值对有多少个,空行相当于是"报头的结束标记",或者是"报头和正文之间的分隔符",HTTP在传输层依赖TCP协议,TCP是面向字节流的,如果没有这个空行,就会出现"粘包问题"

3. HTTP请求

3.1 URL

URL全称:Uniform Resource Locator 统一资源定位符,URL就是平时所说的"网址",互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它

URL基本格式

在这里插入图片描述

一个具体的URL

在这里插入图片描述

user:pass:登陆信息,现在网站进行身份认证基本上不通过URL进行,一般都会省略

端口号:当端口号省略时,浏览器会根据协议类型自动决定使用哪个端口,http协议默认使用80端口,https协议默认使用443端口

/web:带层次的文件路径,表示访问服务器上的不同的资源

片段标识:主要用于页面内跳转,

URL中可以省略的部分

  • 协议名:可以省略,省略后默认为http://
  • ip地址/域名:在HTML中可以省略,(例如img,link,script,a标签中的src或者href属性),省略后表示服务器的ip/域名和当前HTML所属的ip/域名一致
  • 端口号:可以省略,当端口号省略时,浏览器会根据协议类型自动决定使用哪个端口,http协议默认使用80端口,https协议默认使用443端口
  • 带层次的文件路径:可以省略,省略后相当于/. 有些服务器会在发现/路径的时候自动访问/index,html
  • 查询字符串:可以省略,是浏览器给服务器传递的一些参数,使用键值对组织,查询字符串中每个键值对表达的意思,只有设计网站的程序员知道,这些都是程序猿自己规定的
  • 片段标识:可以省略

URL encode

像 / ? : 这样的字符,已经被URL当作特殊意义理解了,因此这些字符不能随意出现,例如:query string中需要带有这些特殊字符,就必须先对特殊字符进行转义

如果query string中包含了上述的这些特殊字符,就可能导致浏览器/服务器解析URL时出错

一个中文字符由UTF-8或者GBK这样的编码方式构成,虽然在URL中没有特殊含义,但是仍然需要进行转义,否则浏览器可能把UTF-8/GBK编码中的某个字节当作URL中的特殊符号

转移规则:将需要转码的字符转成16进制,然后从右到左,取4位,不足4位直接处理,每两位做一位,前面加上%,编码成%XY格式

在这里插入图片描述

例如搜索C++,浏览器就自动将+转义成%2B

URL decode 就是 URL encode的逆过程

3.2 方法

在这里插入图片描述

GET方法

GET是最常用的HTTP方法,常用于获取服务器上的某个资源

触发GET请求的方式:

  • 在浏览器中直接输入URL,此时浏览器就会发送出一个GET请求
  • HTML中的 link,img,script,a等标签也会触发GET请求
  • form表单
  • ajax
  • 使用Java代码/其他的库
  • 通过linux下的wget/curl
  • 通过第三方工具 postman这类工具

使用Fiddler观察GET请求

打开Fiddler,访问搜狗主页,观察抓包结果

在这里插入图片描述

最上面的200 HTTPS www.sogou.com / 是通过浏览器地址栏发送的GET请求

有些是通过HTML中的link/script/img标签产生的,例如

在这里插入图片描述

有些是通过ajax的方式产生的,例如

在这里插入图片描述

选中第一条HTTPS观察请求的详细结果

在这里插入图片描述

GET请求的特点:

  • 首行的第一部分位GET
  • URL的query string可以为空,也可以不为空
  • headr部分有若干个键值对
  • body部分为空,通常清空下,GET请求的body部分为空,也可以自己构造一个body不为空的GET请求

对于GET请求中的URL长度没有任何限制,实际上URL的长度取决于浏览器的实现和HTTP服务器的实现,在浏览器端,不同的浏览器最大长度是不同的,现在的浏览器支持的长度一般都很长,在服务器端,一般这个长度是可以配置的

POST方法

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

触发POST请求的方式

  • form表单
  • ajax
  • 第三方工具

使用Fiddler观察POST方法

在云班课登陆页面,输入账号密码之后,就可以看到POST请求

在这里插入图片描述

POST请求的特点:

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

此时我们可以看到body的内容是在云班课登陆页面输入的账号和密码,数据格式在header中指定:application/json,长度:52

经典面试题:GET和POST的区别

  • 语义不同:GET一般用于获取数据,POST一般用于提交数据;GET也可以用于提交数据,POST也可以用于获取数据
  • 数据位置不同:GET的数据一般通过在URL的query string传递(也可以放在body中传递),POST的数据一般通过body传递(也可以放在URL的query string中传递),
  • GET的body一般为空,也可以不为空;POST的query string一般为空,也可以不为空
  • GET请求一般是幂等的,POST请求一般是不幂等的。标准建议GET实现为幂等的,实际开发中GET也不必完全遵守这个规则,POST也可以设置为幂等的(幂等:如果多次请求得到的结果一样,就视为请求是幂等的)
  • GET可以被缓存,POST不能被缓存,同样也可以通过设置来改变
  • 事实上,GET和POST没有本质上的区别,都是一些习惯用法的区别

关于安全性:是否安全取决于前端在传输密码等敏感信息时是否进行加密,和GET,POST无关;例如GET一般将数据放在URL的query string中,这样用户就可以直接通过URL看到密码,POST一般将数据放在body中,但是可以通过抓包工具也能看到数据内容,

关于传输数据量:标准中没有规定GET的URL的长度,也没有规定POST的body的长度,传输数据量多少,完全取决于不同浏览器和不同服务器之间的实现区别

关于传输数据类型:GET,POST都可以传输文本数据,POST也可以传输二进制数据。GET的query string 虽然无法直接传输二进制数据,但是可以针对二进制数据进行url encode,并且GET也可以将数据放在body中,通过这两个方法,GET请求也可以传输二进制数据。所以针对传输数据类型,GET和POST没有区别,都可以传输文本数据和二进制数据

其他方法
  • PUT与POST相似,只是具有幂等特性,一般用于更新
  • DELETE 删除服务器指定资源
  • OPTIONS 返回服务器所支持的请求方法
  • HEAD类似于GET,只不过响应体不返回,只返回响应头
  • TRACE 回显服务器端收到的请求,测试的时候会用到这个
  • CONNECT预留,暂无使用

4. 认识请求"报头"(header)

header的整体的格式是"键值对"结构

每个键值对占一行,键和值之间使用分号加空格分割

4.1 HOST

标识服务器主机的地址和端口

4.2 Content-Length

表示请求的body中的数据长度,单位是字节

4.3 Content-Type

表示请求的body中的数据格式

常见格式选项:

1、application/x-www-form-urlencoded: form 表单提交的数据格式. 此时 body 的格式形如: title=test&content=hello

2、multipart/form-data: form 表单提交的数据格式(在 form 标签中加上enctyped=“multipart/form-data” . 通常用于提交图片/文件. body 格式形如:

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":"d110a05ccde64b16a861fa2bddfdcd15"}

4.4 User-Agent(UA)

表示浏览器/操作系统的属性,例如:

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36 Edg/101.0.1210.39

其中windows NT 10.0;Win64;64 表示操作系统信息

AppleWebKit后面的内容,表示浏览器信息

UA可以区分PC端和手机端

4.5 Referer

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

在搜狗搜索中输入"鲜花"进行搜索,通过Fiddler进行抓包,查看HTTP请求可以看到如下Referer

Referer: https://www.sogou.com/

表示这个页面是从搜狗搜索这个页面跳转过来的,

如果直接在浏览器中输入URL,或者直接通过收藏夹访问页面时,是没有Referer的

4.6 Cookie

Cookie是一个让浏览器能够存储信息的机制,考虑到安全性,浏览器是禁止网页直接访问计算机的磁盘的,但是在网页开发的时候,又需要能够在网页端保存一些数据,所以就要依赖Cookie

Cookie中存储了一个字符串,这个数据可能是客户端(网页)自行通过JS写入的,也可能来自于服务器(服务器在HTTP响应的header中通过Set-Cookie字段给浏览器返回数据),保存在网页这边的Cookie就会在后续的请求中,自动的带入到请求的报头(header)中

可以通过Cookid实现"身份标识"的功能;每个不同的域名下都可以有不同的Cookie,不同网站之间的Cookie不冲突

通过Fiddler抓包观察登陆页面的过程(以登录CSDN为例);首先要清除之前的cookie,再进行登录

请求

在这里插入图片描述

可以看到,首次登录时,请求的header中没有Cookie

响应

在这里插入图片描述

首次登录的响应中,有Set-Cookie字段,其中的属性值是一串加密后的信息,这个信息就是用户当前登录的身份标识,也称为"令牌"

后续再点击"个人中心时"(访问网站的其他页面时,请求中就会自动带上Cookie),查看请求:

在这里插入图片描述

可以看到,请求的header中已经包含首次登陆时服务器给浏览器返回的Cookie了

理解登录过程

在这里插入图片描述

5. 认识请求"正文"(body)

正文中的内容格式和header中的Content-Type密切相关,可以通过抓包来观察这几种情况

5.1 application/x-www-form-urlencoded

抓取码云上传头像请求

在这里插入图片描述

请求

在这里插入图片描述

在header中可以看到body中的格式类型为:Content-Type:application/x-www-form-urlencoded;body内容是一个键值对结构,avater就是头像,=后面就是图片的具体内容

5.2 multipart/form-data

主要用来上传文件(可以上传比较大的文件),形如这样:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8d5Rp4eJgrUSS3wT

body内容

------WebKitFormBoundary8d5Rp4eJgrUSS3wT
Content-Disposition:form-data;name="file";filename="test.pdf"
Content-Type:application/pdf

hello
------WebKitFormBoundary8d5Rp4eJgrUSS3wT

multipart/form-data表示body中的数据格式类型,boundary表示body的边界,值是一个随机的字符串,通过这个字符串,将body内容包裹起来,正文内容以它开始,以它结束

5.3 application/json

云班课登录的POST请求中,body内容的格式就是json

在这里插入图片描述

json格式以{}包裹,内部有若干个键值对,键值对之间用逗号分割,键和值用冒号分割

6. HTTP响应

6.1 状态码

状态码表示访问一个页面的结果,例如访问成功,访问失败,等等

常见状态码有以下几种

200 OK

这是一个最常见的状态码,表示访问成功

抓包抓到的把部分结果都是200,例如访问搜狗主页

HTTP/1.1 200 OK
Server: nginx
Date: Thu, 10 Jun 2021 06:07:27 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Vary: Accept-Encoding
Set-Cookie: black_passportid=; path=/; expires=Thu, 01 Jan 1970 00:00:00
GMT; domain=.sogou.com
Pragma: No-cache
Cache-Control: max-age=0
Expires: Thu, 10 Jun 2021 06:07:27 GMT
UUID: 80022370-065c-49b0-a970-31bc467ff244
Content-Length: 14805

<!DOCTYPE html><html lang="cn"><head><meta name="viewport"
content="width=device-width,minimum-scale=1,maximum-scale=1,userscalable=
no"><script>window._speedMark = new Date(); window.lead_ip =
'1.80.175.234';
404 Not Found

没有找到资源

浏览器输入一个URL,目的就是为了访问服务器上的一个资源,如果这个URL标识的资源在服务器上不存在,就会出现404,

例如在浏览器中输入www.sogou.com/test.html 此时就在尝试访问sogou服务器上的/test.html这个资源,显然sogou服务器上大概率是没有这个资源的,所以就会出现404

在这里插入图片描述

在这里插入图片描述

403 Forbidden

表示访问被拒绝,有的页面通常需要用户具有一定的权限才能访问,也就是登录后才能访问,如果用户没有登录直接访问,就容易出现403

例如查看码云的私有仓库,如果不登陆,就会出现403,

在这里插入图片描述

405 Method Not Allowed

HTTP中所支持的方法有很多,但是服务器不一定全都支持,此时用户使用了服务器不支持的HTTP方法,就会出现405

500 Internal Server Error

服务器出现内部错误,一般是服务器的代码执行过程中遇到了一些特殊情况,服务器异常崩溃就会产生这个状态码

504 Gateway Timeout

当服务器负载比较大的时候,服务器处理单条请求的时候消耗的时间就会很长,就可能导致出现超时的情况

例如在双十一秒杀时

302 Move temporaily

临时重定向,重定向就是通过这个页面跳转到另一个页面,例如在我们登录CSDN时,输入账号密码登陆成功后,就会跳转到CSDN主页,响应报文的header部分会包含一个Location字段,表示要跳转到哪个页面

例如:码云的登录页面

在这里插入图片描述

可以看到登陆页面响应的首行中,状态码是403,并且在header中有一个Location字段,值就是码云的主页域名,表示要跳转到码云的主页,并且可以在左侧看到,在码云登录页面的HTTP请求下面,紧接着就出现了获取码云主页的HTTP请求

对于302这样的重定向响应来说,body不是必须的,这里的body就是一个简单的HTML,里面就只有一个a标签,万一浏览器没有自动跳转,那么用户手动点击这个a标签也可以跳转

301 Moved Permanently

永久重定向,当浏览器受到这种响应时,后续的请求都会被自动改成新的地址

301也是通过Location字段来表示要重定向到的新的地址

状态码小结
类别原因
1XXInformational(信息性状态码)接收的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求,(自动跳转页面)
4XXClient Error(客户端错误状态码)服务器无法处理请求
5XXServer Error(服务器错误状态码)服务器处理请求出错

6.2 认识响应"报头"(header)

响应报头的基本格式和请求报头的格式基本一致

类似于Content-Type , Content-Lenth等属性的含义和请求中的含义一致

Content-Type

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

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

在CSDN主页,ctrl+F5强制刷新,就能看到以上四种

在这里插入图片描述

  • 第一个黑色字体的HTML请求对应的响应中的Content-Type的值为application/json
  • 蓝色字体:test/html
  • 绿色字体:application/javascript
  • 紫色字体:application/css

6.3 认识响应"正文"(body)

正文的具体格式取决于Content-Type,观察上面几个抓包结果中的响应部分

test/html

在这里插入图片描述

可以看到body中数据格式类型是html

test/css

在这里插入图片描述

可以看到body中数据格式类型是css

application/javascript

在这里插入图片描述

可以看到body中数据格式类型是js

application/json

在这里插入图片描述

可以看到body中的数据格式类型是json

7. 通过form表单构造HTTP请求

form的重要参数:

  • action:构造的HTTP请求的URL
  • method:构造的HTTP请求的方法是GET还是POST(form只支持GET和POST)

7.1form发送GET请求

input的重要参数:

  • type:表示输入框的类型,text表示文本,password表示密码,submit表示提交按钮
  • name:表示构造出来的HTTP请求中query string 的key,输入框中用户输入的内容就是query string的value
  • value:input标签的值,对于type为submit类型来说,value就对应了按钮上显示的文本
<body>
    <form action="http://www.baidu.com">
       账号<input type="text" name="账号">
       密码<input type="password" name="密码" >
       <input type="submit" value="提交">
    </form>
</body>

在这里插入图片描述

在输入框随便输入后,点击提交按钮,就会构造HTTP请求并发送

在这里插入图片描述

构造的HTTP GET请求

在这里插入图片描述

可以看到URL的query string中就出现了我们输入的账号密码,

form代码和HTTP请求之间的关系

在这里插入图片描述

  • form的action属性对应HTTP请求的URL
  • form的method属性对应HTTP请求的方法
  • input的name属性对应query string 的key
  • 用户在input中输入的内容对应query string的value

7.2 form发送POST请求

<body>
    <form action="http://www.baidu.com" method="POST">
       账号<input type="text" name="账号">
       密码<input type="password" name="密码" >
       <input type="submit" value="提交">
    </form>
</body>

构造的HTTP请求

在这里插入图片描述

可以看到通过form发送了POST请求,并且请求的body中包含了我们提交的数据,账号和密码,但是,当前直接给百度提交请求,百度返回的响应中状态码是302,header中Location的地址直接跳转到了出错页面,因为百度不支持像我们自己创建的"账号","密码"这样的参数。

在这里插入图片描述

8. 通过ajax构造HTTP请求

ajax是一种JavaScript给服务器发送HTTP请求的方式,特点是可以不需要刷新页面/页面跳转,就能进行数据传输

8.1 发送GET请求

创建test.html 在script标签中编写以下代码

<script>
        // 构造一个XMLHttpRequest对象
        let httpRequest = new XMLHttpRequest();
        // 注册一个回调函数。处理HTTP响应,异步处理
        httpRequest.onreadystatechange = function(){
            // 0:请求未初始化
            // 1:服务器连接已建立
            // 2:请求已接收
            // 3:请求处理中
            // 4:请求已完成,且响应已就绪
            if(httpRequest.readyState == 4){
                // 打印响应状态码
                console.log(httpRequest.status);
                // 打印响应正文(body)
                console.log(httpRequest.responseText);
            }
        }
        // 构造一个HTTP请求
        httpRequest.open('GET','http://42.192.83.143:8089/AjaxMockServer/info');
        // 发送这个HTTP请求
        httpRequest.send();
    </script>

8.2 发送POST请求

对于POST请求,需要设置body内容

先使用setRequestHeader设置Content-Type,再通过send的参数设置body内容

发送application/x-www-form-urlencoded数据

<script>
        let httpRequest = new XMLHttpRequest();
        httpRequest.onreadystatechange = function(){
            if(httpRequest.readyState == 4){
                console.log(httpRequest.status);
                console.log(httpRequest.responseText);
            }
        }
        httpRequest.open('GET','http://42.192.83.143:8089/AjaxMockServer/info');
        httpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
        httpRequest.send('name=zhangsan&age=18');
    </script>

发送application/json数据

httpRequest.setRequestHeader('Content-Type','application/json')
httpRequest.send({
    name:'zhangsan',
    age:'18'
});

8.3 使用jQuery

使用第三方库封装好的ajax方法来使用,

<!-- 引入jquery第三方库 -->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
        $.ajax({
            type: 'GET',
            url: 'http://42.192.83.143:8089/AjaxMockServer/info',
            success: function(data,status){
                // status就是响应的描述信息,请求是否成功,data就是响应的body
                console.log(status);
                console.log(data);
            }
        });
    </script>

在这里插入图片描述

在浏览器页面加载过程中,可以同时发起多个ajax请求,此时这多个ajax请求相当于是一个并发执行的关系

ajax为了保证安全性,要求发起ajax请求的页面和接收ajax请求的服务器,应该在同一个域名/地址下,默认情况下ajax不允许跨域

8.4 通过Java socket构造HTTP请求

发送HTTP请求,本质上就是按照HTTP的格式,往TCP Socket中写入一个字符串

接收HTTP响应,本质上就是从TCP Socket中读取一个字符串,再按照HTTP的格式来解析

构造一个简单的HTTP客户端程序:

public class HttpClient {
    public String ip;
    public int port;
    public Socket socket;

    public HttpClient(String ip, int port) throws IOException {
        this.ip = ip;
        this.port = port;
        socket = new Socket(ip,port);
    }
    public String get(String url) throws IOException {
        StringBuilder request = new StringBuilder();
        //构造首行
        request.append("GET"+ url + " HTTP/1.1 \n");
        //构造header
        request.append("HOST: "+ip+":"+port+"\n");
        //空行
        request.append("\n");
        OutputStream outputStream = socket.getOutputStream();
        //OutputStream是一个字节流,以字节为单位进行写入的,所以将刚才构造好的request转成byte[]进行发送
        outputStream.write(request.toString().getBytes());
        //读取响应
        InputStream inputStream = socket.getInputStream();
        //创建一个1M的缓冲区,用来存放响应数据
        byte[] buffer = new byte[1024*1024];
        //n表示实际读到的字节数
        int n = inputStream.read(buffer);
        return new String(buffer,0,n,"utf-8");
    }
    public String post(String url , String body) throws IOException {
        StringBuilder request = new StringBuilder();
        request.append("POST" + url + " HTTP/1.1\n");
        request.append("HOST: "+ip+":"+port+"\n");
        request.append("Content-Type: text/plain\n");
        request.append("Content-Length: "+ body.getBytes().length+"\n");
        request.append("\n");
        request.append(body);
        //发送请求
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(request.toString().getBytes());
        //读取响应
        InputStream inputStream = socket.getInputStream();
        byte[] buffer = new byte[1024*1024];
        int n = inputStream.read(buffer);
        return new String(buffer,0,n,"utf-8");
    }

    public static void main(String[] args) throws IOException {
        HttpClient httpClient = new HttpClient("42.192.83.143",8089);
        String response = httpClient.get("/AjaxMockServer/info");
        System.out.println(response);
        String resp = httpClient.post("/AjaxMockServer/info","这儿是POST请求的正文");
        System.out.println(resp);
    }
}

使用Java构造的HTTP客户端不再有"跨域"的限制了,此时也可以用来获取其他服务器的数据

跨域只是浏览器的行为,对于ajax有效,对于其他语言来说一般都和跨域无关

9. HTTPS

HTTPS也是一个应用层协议,只是在HTTP协议的基础上引入了一个加密层(SSL)

HTTP协议内容都是按照文本的方式明文传输的,这就导致在传输过程中出现一些被篡改的情况,由于我们通过网络传输的任何数据包都会经过运营商的网络设备(路由器,交换机等),那么运营商的网络设备就可以解析出你传输的数据内容,并进行篡改,不止运营商可以劫持,其他的黑客也可以用类似的手段进行劫持,来窃取用户隐私信息,或者篡改内容,在互联网上明文传输是比较危险的事情

HTTPS就是在HTTP的基础上进行了加密,来保证用户的信息安全

9.1 加密

加密就是把明文(要传输的信息)进行一系列的变换,生成密文,

解密就是把密文,再进行一系列的变换,还原成明文

在这个加密和解密的过程中,往往需要一个或者多个中间的数据,辅助进行这个过程,这样的数据称为密钥

9.2 HTTPS的工作过程

加密的方式有很多,整体可以分为两大类:对称加密和非对称加密

1. 引入对称加密

对称加密起始就是通过同一个"密钥",把明文加密成密文,也能把密文解密成明文

在这里插入图片描述

引入对称加密之后,即使黑客通过入侵路由器截获了数据,因为没有密钥,就无法对密文进行解密,也就不知道数据的真实内容了,

但是因为服务器是同一时刻给很多客户端提供服务的,这些客户端的密钥都不相同,所以服务器就需要维护每个客户端和每个密钥之间的关联关系,

在这里插入图片描述

比较理想的做法,就是在客户端和服务器建立连接的时候,双方协商确定这次的密钥是啥

在这里插入图片描述

但是如果直接把密钥明文传输,那么黑客也就能获得密钥了,那加密操作就毫无意义了,

所以密钥的传输也必须加密传输

但是想要对密钥进行对称加密,就仍然需要先协商确定一个"密钥的密钥",这就无限套娃了,

所以针对密钥加密需要引入非对称加密

2. 引入非对称加密

非对称加密需要用到两个密钥,一个叫"公钥",一个叫"私钥"

公钥和私钥是配对的,最大的缺点就是运算速度非常慢,比对称加密要慢很多,成本比对称加密高

通过公钥对明文进行加密,再通过私钥对密文进行解密。也可以反着用

在这里插入图片描述

  • 客户端再本地生成对称密钥,通过公钥加密,发送给服务器
  • 由于中间的网络设备没有私钥,即使截获了数据,也无法还原出内部的原文,也就无法获得对称加密的密钥
  • 服务器通过私钥对密文进行解密,得到了对称加密的密钥,并且使用这个对称密钥将要给客户端返回的数据进行加密
  • 后续客户端和服务器的通信都只用对称加密即可,由于该密钥只有客户端和服务器持有,其他主机/设备不知道密钥,即使数据被截获也没有影响

由于对称加密的效率比非对称加密高很多,因此只是在开始阶段协商密钥的时候使用非对称加密,后续的传输仍然使用对称加密,将对称加密和非对称加密进行结合,非对称加密用来针对"对称加密的密钥"进行加密,对称加密用来传输数据。这样既保证了安全性,降低了成本,也提高了效率

客户端如何获取到公钥呢?是在客户端和服务器连接建立之初,服务器将公钥发送给客户端,如果黑客在中间进行偷梁换柱,首先截获服务器发送给客户端的真正的公钥,再伪造一对公钥和私钥,私钥自己持有,公钥给客户端,这时客户端用这个公钥对于对称密钥进行加密,再发送给服务器时,黑客就可以用自己的私钥对密文进行解密,就知道了本次连接的对称加密的密钥,进而将这个对称密钥使用服务器真正的公钥进行加密,再发送给客户端。这时黑客知道了对称加密的密钥,对于客户端和服务器的数据交互就了如指掌了。这就是中间人攻击

3. 引入证书

为了解决中间人攻击问题,就可以在客户端和服务器刚一建立连接的时候,服务器给客户端返回一个证书,这个证书包含了公钥,也包含了网站的身份信息

在这里插入图片描述

这个证书可以理解成是一个结构化的字符串,包含:

  • 证书发布机构
  • 证书有效期
  • 公钥
  • 证书所有者
  • 签名等

当客户端获取到这个证书之后,会对证书进行校验,防止证书是伪造的

  • 判定证书的有效期是否过期
  • 判定证书的发布机构是否受信任,(在操作系统中已内置的受信任的证书发布机构)
  • 验证证书是否被篡改:从系统中拿到该证书发布机构的公钥,对签名解密,得到一个hash值,设为hash1,然后计算整个证书的hash值,设为hash2,对于hash1和hash2是否相等,如果相等,说明证书是没有被篡改过的

9.3 小结

HTTPS传输过程

  1. 客户端先从服务器获取证书,证书中包含了公钥
  2. 客户端对证书进行校验
  3. 客户端生成一个对称密钥,使用公钥对对称密钥进行加密,发送给服务器
  4. 服务器得到这个请求之后,使用私钥进行解密,得到对称密钥
  5. 客户端发出后续的请求,后续的请求都是使用这个对称密钥加密的
  6. 客户端服务器收到的数据也都是使用这个对称密钥进行解密的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值