HTTP

🌷 理解 HTTP 协议的工作过程

当我们在浏览器中输入一个 “网址”, 此时浏览器就会给对应的服务器发送一个 HTTP 请求. 对方服务器收到这个请求之后, 经过计算处理, 就会返回一个 HTTP 响应.
image.png
事实上, 当我们访问一个网站的时候, 可能涉及不止一次的 HTTP 请求/响应 的交互过程.
可以通过 chrome 的开发者工具观察到这个详细的过程.
通过 F12 打开 chrome 的开发者工具, 切换到 Network 标签页. 然后刷新页面即可看到如下图效果. 每一条记录都是一次 HTTP 请求/响应
image.png
注意:当前 搜狗主页 是通过 https 来进行通信的. https 是在 http 基础之上做了一个加密解密的工作, 后面再介绍.

🌷 HTTP 协议格式

HTTP 是一个文本格式的协议. 可以通过 Chrome 开发者工具或者 Fiddler 抓包, 分析 HTTP 请求/响应的细节.
抓包工具的使用
Fiddler 为例. (下载地址: https://www.telerik.com/fiddler/)
安装过程比较简单, 一路 next 即可.
image.png

左侧窗口显示了所有的 HTTP请求/响应, 可以选中某个请求查看详情.
右侧上方显示了 HTTP 请求的报文内容. (切换到 Raw 标签页可以看到详细的数据格式)
右侧下方显示了 HTTP 响应的报文内容. (切换到 Raw 标签页可以看到详细的数据格式)
请求和响应的详细数据, 可以通过右下角的 View in Notepad 通过记事本打开.
可以使用 ctrl + a 全选左侧的抓包结果, delete 键清除所有被选中的结果.

抓包工具的原理
Fiddler 相当于一个 “代理”.
浏览器访问 sogou.com 时, 就会把 HTTP 请求先发给 Fiddler, Fiddler 再把请求转发给 sogou 的服务器.
当 sogou 服务器返回数据时, Fiddler 拿到返回数据, 再把数据交给浏览器.
因此 Fiddler 对于浏览器和 sogou 服务器之间交互的数据细节, 都是非常清楚的.
image.png

协议格式:
在这里插入图片描述
在这里插入图片描述

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

🌷 HTTP 请求 (Request)

⭐️ 认识 URL

URL 基本格式
平时我们俗称的 “网址” 其实就是说的 URL (Uniform Resource Locator 统一资源定位符).
互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它.
image.png

一个具体的 URL:

https://v.bitedu.vip/personInf/student?userId=10000&classId=100

可以看到, 在这个 URL 中有些信息被省略了.
https : 协议方案名. 常见的有 http 和 https, 也有其他的类型. (例如访问 mysql 时用的
jdbc:mysql )
user:pass : 登陆信息. 现在的网站进行身份认证一般不再通过 URL 进行了. 一般都会省略
v.bitedu.vip : 服务器地址. 此处是一个 “域名”, 域名会通过 DNS 系统解析成一个具体的 IP 地址.
(通过 ping 命令可以看到, v.bitedu.vip 的真实 IP 地址为 118.24.113.28 )
端口号: 上面的 URL 中端口号被省略了. 当端口号省略的时候, 浏览器会根据协议类型自动决定使用
哪个端口. 例如 http 协议默认使用 80 端口, https 协议默认使用 443 端口.
/personInf/student : 带层次的文件路径.
userId=10000&classId=100 : 查询字符串(query string). 本质是一个键值对结构. 键值对之间使
用 & 分隔. 键和值之间使用 = 分隔.
片段标识: 此 URL 中省略了片段标识. 片段标识主要用于页面内跳转. (例如 Vue 官方文档: https://cn.vuejs.org/v2/guide/#%E8%B5%B7%E6%AD%A5, 通过不同的片段标识跳转到文档的不同章节)

使用 ping 命令查看域名对应的 IP 地址.

  1. 在开始菜单中输入 cmd , 打开 命令提示符
  2. 在 cmd 中输入 ping v.bitedu.vip , 即可看到域名解析的结果.

关于 query string
query string 中的内容是键值对结构. 其中的 key 和 value 的取值和个数, 完全都是程序猿自己约
定的. 我们可以通过这样的方式来自定制传输我们需要的信息给服务器.

URL 中的可省略部分

  • 协议名: 可以省略, 省略后默认为 http://
  • ip 地址 / 域名: 在 HTML 中可以省略(比如 img, link, script, a 标签的 src 或者 href 属性). 省 略后表示服务器的 ip / 域名与当前 HTML 所属的 ip / 域名一致.
  • 端口号: 可以省略. 省略后如果是 http 协议, 端口号自动设为 80; 如果是 https 协议, 端口号自动设为 443.
  • 带层次的文件路径: 可以省略. 省略后相当于 / . 有些服务器会在发现 / 路径的时候自动访问 /index.html
  • 查询字符串: 可以省略
  • 片段标识: 可以省略

⭐️ 认识 “方法” (method)

在这里插入图片描述

  1. GET 方法
    GET 是最常用的 HTTP 方法. 常用于获取服务器上的某个资源.
    在浏览器中直接输入 URL, 此时浏览器就会发送出一个 GET 请求.
    另外, HTML 中的 link, img, script 等标签, 也会触发 GET 请求.

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

  1. POST 方法
    POST 方法也是一种常见的方法. 多用于提交用户输入的数据给服务器(例如登陆页面).
    通过 HTML 中的 form 标签可以构造 POST 请求, 或者使用 JavaScript 的 ajax 也可以构造 POST 请求.

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

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

⭐️ 认识请求 “报头” (header)

header 的整体的格式也是 “键值对” 结构.
每个键值对占一行. 键和值之间使用分号分割.
Host
表示服务器主机的地址和端口.
Content-Length
表示 body 中的数据长度.
Content-Type
表示请求的 body 中的数据格式.
常见选项:

  • application/x-www-form-urlencoded: form 表单提交的数据格式. 此时 body 的格式形如: title=test&content=hello
  • multipart/form-data: form 表单提交的数据格式(在 form 标签中加上 enctyped=“multipart/form-data” . 通常用于提交图片/文件.
  • application/json: 数据为 json 格式. body 格式形如:{“username”:“123456789”,“password”:“xxxx”,“code”:“jw7l”}

User-Agent (简称 UA)
表示浏览器/操作系统的属性. 形如:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36
其中 Windows NT 10.0; Win64; x64 表示操作系统信息
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 表示浏览器信息.
Referer
表示这个页面是从哪个页面跳转过来的.
如果直接在浏览器中输入URL, 或者直接通过收藏夹访问页面时是没有 Referer 的.
Cookie
Cookie 中存储了一个字符串, 这个数据可能是客户端(网页)自行通过 JS 写入的, 也可能来自于服务器(服务器在 HTTP 响应的 header 中通过 Set-Cookie 字段给浏览器返回数据). 往往可以通过这个字段实现 “身份标识” 的功能.
每个不同的域名下都可以有不同的 Cookie, 不同网站之间的 Cookie 并不冲突.

⭐️ 认识请求 “正文” (body)

正文中的内容格式和 header 中的 Content-Type 密切相关. 上面也罗列了三种常见的情况.

🌷 HTTP 响应详解

⭐️ 认识 “状态码” (status code)

状态码表示访问一个页面的结果. (是访问成功, 还是失败, 还是其他的一些情况…).
以下为常见的状态码.
HTTP 状态码是服务器端返回给客户端的响应状态码,根据(HTTP)状态码我们就能知道服务器端想要给客户端表达的具体含义,比如 200 就表示请求访问成功,500 就表示服务器端程序出错等。 HTTP 状态码可分为 5 大类:

1XX:消息状态码。
2XX:成功状态码。
3XX:重定向状态码。
4XX:客户端错误状态码。
5XX:服务端错误状态码。
而这 5 大类中又包含了很多具体的状态码。

1XX

消息状态码,其中:

100:Continue 继续。客户端应继续其请求。
101:Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到 HTTP 的新版本协议。

2XX

成功状态码,其中:

200:OK 请求成功。一般用于 GET 与 POST 请求。
201:Created 已创建。成功请求并创建了新的资源。
202:Accepted 已接受。已经接受请求,但未处理完成。
203:Non-Authoritative Information 非授权信息。请求成功。但返回的 meta 信息不在原始的服务器,而是一个副本。
204:No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档。
205:Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域。
206:Partial Content 部分内容。服务器成功处理了部分 GET 请求。

3XX

重定向状态码,其中:

300:Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择。
301:Moved Permanently 永久移动。请求的资源已被永久的移动到新 URI,返回信息会包括新的 URI,浏览器会自动定向到新 URI。今后任何新的请求都应使用新的 URI 代替。
302:Found 临时移动,与 301 类似。但资源只是临时被移动。客户端应继续使用原有URI。
303:See Other 查看其它地址。与 301 类似。使用 GET 和 POST 请求查看。
304:Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源。
305:Use Proxy 使用代理。所请求的资源必须通过代理访问。
306:Unused 已经被废弃的 HTTP 状态码。
307:Temporary Redirect 临时重定向。与 302 类似。使用 GET 请求重定向。

4XX

客户端错误状态码,其中:

400:Bad Request 客户端请求的语法错误,服务器无法理解。
401:Unauthorized 请求要求用户的身份认证。
402:Payment Required 保留,将来使用。
403:Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求。
404:Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面。
405:Method Not Allowed 客户端请求中的方法被禁止。
406:Not Acceptable 服务器无法根据客户端请求的内容特性完成请求。
407:Proxy Authentication Required 请求要求代理的身份认证,与 401 类似,但请求者应当使用代理进行授权。
408:Request Time-out 服务器等待客户端发送的请求时间过长,超时。
409:Conflict 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突。
410:Gone 客户端请求的资源已经不存在。410 不同于 404,如果资源以前有现在被永久删除了可使用 410 代码,网站设计人员可通过 301 代码指定资源的新位置。
411:Length Required 服务器无法处理客户端发送的不带 Content-Length 的请求信息。
412:Precondition Failed 客户端请求信息的先决条件错误。
413:Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个 Retry-After 的响应信息。
414:Request-URI Too Large 请求的 URI 过长(URI通常为网址),服务器无法处理。
415:Unsupported Media Type 服务器无法处理请求附带的媒体格式。
416:Requested range not satisfiable 客户端请求的范围无效。
417:Expectation Failed 服务器无法满足 Expect 的请求头信息。

5XX

服务端错误状态码,其中:

500:Internal Server Error 服务器内部错误,无法完成请求。
501:Not Implemented 服务器不支持请求的功能,无法完成请求。
502:Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应。
503:Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中。
504:Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求。
505:HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理。

⭐️ 认识响应 “报头” (header)

响应报头的基本格式和请求报头的格式基本一致.
类似于 Content-Type , Content-Length 等属性的含义也和请求中的含义一致.
Content-Type
响应中的 Content-Type 常见取值有以下几种:

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

⭐️ 认识响应 “正文” (body)

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

1) text/html

<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible 
content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta 
name=viewport content="width=device-width,initial-scale=1,minimumscale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=/favicon.ico>
<title id=bodyTitle>比特教务管理系统</title><link 
href=https://cdn.bootcss.com/jquerydatetimepicker/2.5.20/jquery.datetimepicker.css rel=stylesheet><script 
src=https://cdn.bootcss.com/highlight.js/9.1.0/highlight.min.js></script><script 
src=https://cdn.bootcss.com/highlightjs-line-numbers.js/2.5.0/highlightjs-linenumbers.min.js></script><style>html,
   body,
   #app {
     height: 100%;
     margin: 0px;
     padding: 0px;
   }
   .chromeframe {
     margin: 0.2em 0;
     background: #ccc;
     color: #000;
     padding: 0.2em 0;
   }
  ......

2) text/css

@font-face{font-family:element-icons;src:url(../../static/fonts/elementicons.535877f5.woff) format("woff"),url(../../static/fonts/elementicons.732389de.ttf) format("truetype");font-weight:400;font-style:normal}
[class*=" el-icon-"], 
......

3) application/javascript

(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["app"],
{0:function(t,e,n){t.exports=n("56d7")},"00b3":function(t,e,n){},"
......

4) application/json

{"msg":"操作成功","code":200,"permissions":[] }

⭐️ 通过 form 表单构造 HTTP 请求

form (表单) 是 HTML 中的一个常用标签. 可以用于给服务器发送 GET 或者 POST 请求.
form 的重要参数:

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

input 的重要参数:

  • type: 表示输入框的类型. text 表示文本, password 表示密码, submit 表示提交按钮.
  • name: 表示构造出的 HTTP 请求的 query string 的 key. query string 的 value 就是输入框的用户输入的内容.
  • value: input 标签的值. 对于 type 为 submit 类型来说, value 就对应了按钮上显示的文本.

⭐️ form 发送 GET 请求

<form action="http://abcdef.com/myPath" method="GET">
	<input type="text" name="userId">
	<input type="text" name="classId">
	<input type="submit" value="提交">
</form>

页面展示的效果:
在这里插入图片描述
在输入框随便填写数据,
image.png
点击 “提交”, 此时就会构造出 HTTP 请求并发送出去.
构造的 HTTP 请求

GET http://abcdef.com/myPath?userId=100&classId=200 HTTP/1.1
Host: abcdef.com
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/91.0.4472.114 Safari/537.36
Accept: 
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag
e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

**注意: **由于我们的服务器的地址是随便写的, 因此无法获取到正确的 HTTP 响应.
体会 form 代码和 HTTP 请求之间的对应关系:
在这里插入图片描述

  • form 的 action 属性对应 HTTP 请求的 URL
  • form 的 method 属性对应 HTTP 请求的方法
  • input 的 name 属性对应 query string 的 key
  • input 的 内容 对应 query string 的 value

⭐️ form 发送 POST 请求

修改上面的代码, 把 form 的 method 修改为 POST,页面效果不变.

<form action="http://abcdef.com/myPath" method="POST">
	<input type="text" name="userId">
	<input type="text" name="classId">
	<input type="submit" value="提交">
</form>

构造的 HTTP 请求:

POST http://abcdef.com/myPath HTTP/1.1
Host: abcdef.com
Proxy-Connection: keep-alive
Content-Length: 22
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/91.0.4472.114 Safari/537.36
Accept: 
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag
e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

userId=100&classId=200

主要的区别:

  • method 从 GET 变成了 POST
  • 数据从 query string 移动到了 body 中.

使用 form 还可以提交文件. 后面再介绍.

⭐️ 通过 ajax 构造 HTTP 请求

从前端角度, 除了浏览器地址栏能构造 GET 请求, form 表单能构造 GET 和 POST 之外, 还可以通过 ajax的方式来构造 HTTP 请求. 并且功能更强大.
ajax 全称 Asynchronous Javascript And XML, 是 2005 年提出的一种JavaScript 给服务器发送 HTTP 请求的方式. 特点是可以不需要 刷新页面/页面跳转 就能进行数据传输.

发送 GET 请求

要通过 Ajax 构造 HTTP 请求,需要使用 JavaScript 中的 XMLHttpRequest 对象。以下是一个简单的示例,演示如何使用 Ajax 向服务器发送 GET 请求:

// 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();

// 设置请求方法和 URL
xhr.open('GET', 'https://example.com/api/data');

// 设置响应类型
xhr.responseType = 'json';

// 监听请求状态变化
xhr.onreadystatechange = function() {
  if (xhr.readyState === XMLHttpRequest.DONE) {
    if (xhr.status === 200) {
      // 成功接收到响应
      console.log(xhr.response);
    } else {
      // 请求失败
      console.log('请求失败: ' + xhr.status);
    }
  }
};

// 发送请求
xhr.send();

在上面的示例中,首先创建了一个 XMLHttpRequest 对象,并设置了请求方法和 URL。然后设置了响应类型为 JSON。接下来监听了 XMLHttpRequest 对象的 onreadystatechange 事件,该事件在请求状态发生变化时被触发。最后使用 send() 方法发送请求。当接收到响应时,可以通过 response 属性访问响应数据。如果请求失败,可以通过 status 属性获取 HTTP 状态码。

当使用 Ajax 构造 HTTP 请求时,可以通过 XMLHttpRequest 对象设置并发送请求。以下是一些常用的方法和属性:

  • open(method, url):设置请求方法和 URL。method 参数表示 HTTP 请求方法,如 GET、POST 等;url 参数表示请求的 URL。
  • setRequestHeader(name, value):设置 HTTP 请求头的值。name 参数表示请求头的名称,如 Content-Type、Authorization 等;value 参数表示请求头的值。
  • send(data):发送 HTTP 请求。data 参数表示请求体的数据,对于 GET 请求,该参数通常为空。
  • onreadystatechange:当请求状态发生变化时触发的事件。可以通过 readyState 和 status 属性判断请求的状态和响应的 HTTP 状态码。
  • readyState:表示请求的状态,有 5 种取值,分别是 0(未初始化)、1(已连接)、2(已发送)、3(已接收)、4(已完成)。
  • status:表示响应的 HTTP 状态码,如 200、404 等。
  • responseType:表示响应的数据类型,有 5 种取值,分别是 “”(默认值,表示字符串)、“text”(表示字符串)、“json”(表示 JSON 对象)、“document”(表示 HTML 文档对象)、“arraybuffer”(表示二进制数据)。

除了使用原生的 XMLHttpRequest 对象,还可以使用许多现代的 JavaScript 框架和库来简化 Ajax 请求的编写,如 jQuery、axios、fetch 等。

浏览器和服务器交互过程(引入 ajax 后):

  1. 用户在页面上触发一个事件,比如点击按钮。
  2. 页面使用 JavaScript 代码创建一个 XMLHttpRequest 对象。
  3. JavaScript 代码使用 XMLHttpRequest 对象向服务器发送 HTTP 请求,可以是 GET 或 POST 请求,请求的 URL 通常是一个 API 接口。
  4. 服务器接收到请求后,处理请求并返回响应数据。
  5. XMLHttpRequest 对象接收到响应数据,可以是 XML、JSON、文本或二进制数据。
  6. JavaScript 代码解析响应数据并更新页面,通常使用 DOM 操作或数据绑定技术。

发送 POST 请求

要发送 POST 请求,需要使用 XMLHttpRequest 对象的 open() 方法设置请求方法和 URL,并使用 send() 方法发送请求体的数据。

以下是一个简单的示例,演示如何使用 Ajax 向服务器发送 POST 请求:

// 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();

// 设置请求方法和 URL
xhr.open('POST', 'https://example.com/api/data');

// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/json');

// 设置响应类型
xhr.responseType = 'json';

// 监听请求状态变化
xhr.onreadystatechange = function() {
  if (xhr.readyState === XMLHttpRequest.DONE) {
    if (xhr.status === 200) {
      // 成功接收到响应
      console.log(xhr.response);
    } else {
      // 请求失败
      console.log('请求失败: ' + xhr.status);
    }
  }
};

// 发送请求体数据
var requestBody = {
  name: 'John Doe',
  email: 'john.doe@example.com'
};
xhr.send(JSON.stringify(requestBody));

首先创建了一个 XMLHttpRequest 对象,并使用 open() 方法设置了请求方法和 URL。然后使用 setRequestHeader() 方法设置了请求头的类型为 JSON。接下来设置了响应类型为 JSON。然后监听了 XMLHttpRequest 对象的 onreadystatechange 事件,当请求状态发生变化时被触发。最后使用 send() 方法发送请求体的数据,该数据需要使用 JSON.stringify() 方法将 JavaScript 对象转换为字符串。

需要注意的是,POST 请求通常需要在请求头中设置 Content-Type,表示请求体的数据类型。对于 JSON 数据,应该将其设置为 application/json。此外,由于 POST 请求通常会包含敏感信息,因此应该使用 HTTPS 协议进行加密传输,以保证数据的安全。

通过 Java socket 构造 HTTP 请求
所谓的 “发送 HTTP 请求”, 本质上就是按照 HTTP 的格式往 TCP Socket 中写入一个字符串.
所谓的 “接受 HTTP 响应”, 本质上就是从 TCP Socket 中读取一个字符串, 再按照 HTTP 的格式来解析.
我们基于 Socket 的知识, 完全可以构造出一个简单的 HTTP 客户端程序, 用来发送各种类型的 HTTP 请求.

要通过 Java socket 构造 HTTP 请求,需要了解 HTTP 协议的格式和规范。HTTP 协议是一种基于文本的协议,请求和响应都是由一些头部字段和可选的主体部分组成的。以下是一个简单的 HTTP 请求的格式:

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Upgrade-Insecure-Requests: 1

发送 GET 请求:

import java.io.*;
import java.net.Socket;

public class HttpGetRequest {
    public static void main(String[] args) throws IOException {
        // 创建 Socket 对象
        Socket socket = new Socket("www.example.com", 80);

        // 构造 HTTP 请求
        String request = "GET /index.html HTTP/1.1\r\n" +
                "Host: www.example.com\r\n" +
                "User-Agent: Java/1.8.0_291\r\n" +
                "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n" +
                "Accept-Language: en-US,en;q=0.5\r\n" +
                "Accept-Encoding: gzip, deflate, br\r\n" +
                "Connection: keep-alive\r\n" +
                "\r\n";

        // 发送 HTTP 请求
        OutputStream outputStream = socket.getOutputStream();
        PrintWriter writer = new PrintWriter(outputStream, true);
        writer.println(request);

        // 接收 HTTP 响应
        InputStream inputStream = socket.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }

        // 关闭 Socket 连接
        socket.close();
    }
}

需要注意的是,HTTP 请求和响应都是基于文本的协议,因此在发送和接收时需要使用相应的字符流进行处理。此外,构造 HTTP 请求时需要按照协议的规范编写请求行和头部字段,否则服务器可能无法正确解析请求。

🌷 HTTPS 执行流程(必问)

HTTPS 执行流程如下:

  1. 客户端使用 HTTPS 访问服务器端。
  2. 服务器端返回数字证书,以及使用非对称加密,生成一个公钥给客户端(私钥服务器端自己保留)。
  3. 客户端验证数字证书是否有效,如果无效,终止访问,如果有效(浏览器去做):
    1. 使用对称加密生成一个共享秘钥;
    2. 使用对称加密的共享秘钥加密数据;
    3. 使用非对称加密的公钥加密(对称加密生成的)共享秘钥。
    4. 发送加密后的秘钥和数据给服务器端。
  4. 服务器端使用私钥解密出客户端(使用对称加密生成的)共享秘钥,再使用共享秘钥解密出数据的具体内容.
  5. 之后客户端和服务器端就使用共享秘钥加密的内容内容进行交互了。

如下图所示:image.png

常见加密:
对称加密:使用相同的密钥进行加密和解密的算法。发送方和接收方必须共享密钥才能进行通信,这使得对称加密算法在保密性和性能方面非常高效。常见的对称加密算法包括 AES(高级加密标准)和 DES(数据加密标准)。
非对称加密:也称为公钥加密,使用一对密钥,即公钥和私钥。发送方使用接收方的公钥进行加密,而接收方使用其私钥进行解密。非对称加密算法可以实现加密和数字签名等功能。常见的非对称加密算法包括 RSA 和 ECC(椭圆曲线加密)。
哈希函数:也称为散列函数,将任意长度的输入数据映射为固定长度的输出值(哈希值)。哈希函数通常用于验证数据的完整性,常见的哈希函数包括 MD5、SHA-1、SHA-256 等。哈希函数是不可逆的,即无法从哈希值还原出原始输入。

为什么HTTPS同时使用两种加密?
HTTPS 第一次使用的是非对称加密,之后使用对称加密,其原因是,第一次要保证通讯安全,所以非对称加密是最好的选择,而之后,因为已经建立了安全通讯,并且后面传输数据也要考虑通讯的效率问题,所以使用对称加密,及兼顾安全(对称加密秘钥使用非对称加密来保证)同时效率又高。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值