- URL 本身(即协议部分 http:// 或 https://)不会被加密 无论是 HTTP 还是 HTTPS,浏览器发请求时,域名和路径(URL)始终是明文的 ,不会被 TLS 加密。 被加密的只有 Header 和 Body 的内容。
- HTTPS 加密的是什么?
- 请求的 Header(包括 Cookie、Authorization、Host 等字段)→ 加密
- 请求的 Body(POST 数据、上传文件等)→ 加密
- 响应的 Header 和 Body → 加密 但 https://example.com/login 这个完整的 URL 字符串,在传输过程中是明文的(DNS 查询和 TLS 握手阶段都能看到域名)。
- 服务器收到请求后可以做最终校验 即使中间人只能看到明文的 URL(比如 https://example.com/api/v1/user),也无法看到:
- Header 里你传的 token、Cookie
- Body 里你提交的密码、个人信息 服务器拿到请求后,会对比:
- URL 中写的路径(明文可见)
- Header 中的 Host 字段(加密传输,只有服务器能解密看到) 如果两者不一致(比如 URL 是 example.com,但 Host 头被篡改为 fake.com),服务器可以拒绝这个请求,从而防止某些中间人攻击。

header 的整体的格式也是"键值对"结构.
每个键值对占一行.键和值之间使用分号分割. 报头的种类有很多,此处仅介绍几个常见的.
Host:表示服务器主机的地址和端口.
Content-Length表示body中的数据长度.
Content-Type 表示请求的body中的数据格式.

常见选项:
• application/x-www-form-urlencoded: form 表单提交的数据格式.此时body的格式形如:
java
title=test&content=hello
• multipart/form-data: form 表单提交的数据格式(在form标签中加上 enctyped="multipart/form-data" .通常用于提交图片/文件.body格式形如:
java
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3Trw------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--
• application/json: 数据为json格式.body格式形如
java
{"username":"123456789","password":"xxxx","code":"jw7l","uuid":"d110a05ccde64b1
关于 Content-Type 的详细情况:https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types
User-Agent (简称UA):
其中 Windows NT 10.0;
Win64; x64 表示操作系统信息
AppleWebKit/537.36 (KHTML, like Gecko) 游览器内核
Chrome/91.0.4472.77 Safari/537.36 表⽰浏览器信息.
User-Agent 之所以是这个样⼦是因为历史遗留问题.可以参考 User-Agent 的故事:https://zhuanlan.zhihu.com/p/398807396
表示浏览器/操作系统的属性.形如
java
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko

- 通过 UA 中的浏览器版本/操作系统版本,区分出当前用户的设备,最多都支持哪些特性

- UA也可以区分用户的设备,移动端还是PC端

响应式编程:根据屏幕尺寸自动切换样式
Referer 表示这个页面是从哪个页面跳转过来的.形如

如果直接在浏览器中输⼊URL,或者直接通过收藏夹访问页面时是没有Referer的.
Cookie
Cookie 中存储了⼀个字符串,这个数据可能是客户端(网页)自行通过JS写入的,也可能来自于服务器 (服务器在HTTP响应的header中通过Set-Cookie字段给浏览器返回数据). 往往可以通过这个字段实现"⾝份标识"的功能.
每个不同的域名下都可以有不同的Cookie,不同网站之间的Cookie并不冲突. 可以通过抓包观察页面登陆的过程(以码云为例):


- 你在浏览器输入 https://example.com 回车 → 首先发 3 个 TCP 握手包(这时候根本没有 Cookie!) → 握手成功 + TLS 握手完成
- 浏览器真正开始发第一个 HTTP 请求(GET /) → 这个请求的数据包里才第一次可能出现 Cookie Header → 如果你之前没来过这个网站,Cookie 头是空的 → 如果你来过,浏览器会自动把之前 Set-Cookie 存的 cookie 塞进去
- 你点登录、加购物车、翻页...... → 每点一次,就发一个新的 HTTP 请求数据包 → 每个包里都带着同样的 Cookie Header(除非服务器改了它)

右键可以删除,清空
重启访问服务器就可以找回了
为什么请求没有 Cookie,但响应却有 Set-Cookie?
服务器根本不关心你这次请求有没有带 Cookie,只要你访问了它,它就会"趁机"给你种新的 Cookie(或者重新种一遍)。

1) 清除之前的cookie
为了方便观察,先清除掉之前登陆的cookie
在码云页⾯上,点击url左侧的图标,选择Cookie


然后移除已经存在的Cookie


- 登陆操作 登陆请求
java
POST https://gitee.com/login HTTP/1.1
Host: gitee.com
Connection: keep-alive
Content-Length: 394
Cache-Control: max-age=0
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
Origin: https://gitee.com
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/w
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://gitee.com/login
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
encrypt_key=password&utf8=%E2%9C%93&authenticity_token=36ZqO9tglSN6EB6pF6f2Gt%2B
登陆响应
java
HTTP/1.1 302 Found
Date: Thu, 10 Jun 2021 04:15:58 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Keep-Alive: timeout=60
Server: nginx
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: chrome=1
Expires: Sun, 1 Jan 2000 01:00:00 GMT
Pragma: must-revalidate, no-cache, private
Location: https://gitee.com/HGtz2222
Cache-Control: no-cache
Set-Cookie: oschina_new_user=false; path=/; expires=Mon, 10 Jun 2041 04:16:00 -0
Set-Cookie: gitee_user=true; path=/
Set-Cookie: gitee-session-n=M1Rhbk1QUUxQdWk1VEZVQ1BvZXYybG13ZUJFNGR1V0pSYTZyTllE
X-Request-Id: 77f12d095edc98fab27d040a861f63b1
X-Runtime: 0.166621
Content-Length: 92
<html><body>You are being <a href="https://gitee.com/HGtz2222">redirected</a>.</
- 访问其他⻚⾯ 登陆成功之后,此时可以看到后续访问码云的其他页面(比如个人主页),请求中就都会带着刚才获取到 的Cookie信息
java
GET https://gitee.com/HGtz2222 HTTP/1.1
Host: gitee.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/w
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
sec-ch-ua-mobile: ?0
Referer: https://gitee.com/login
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: oschina_new_user=false; user_locale=zh-CN; yp_riddler_id=1ce4a551-a160-4
理解登陆过程



一次会话(Session)的准确定义:
从客户端与服务器建立认证关系(通常是登录)开始,到以下任意一种情况结束的整个过程:
- 用户主动退出登录
- Session 超时(常见 30 分钟不操作自动过期)
- 用户关闭浏览器(部分实现会销毁)
- 服务器主动销毁(踢人、下线)
这段时间内,用户发出的 所有 HTTP 请求 都属于同一次会话。
响应报头(服务器 → 浏览器)了解

认识请求"正⽂"(body)
正文中的内容格式和header中的Content-Type密切相关.上面也罗列了三种常见的情况. 下⾯可以通过抓包来观察这几种情况:
1) application/x-www-form-urlencoded 抓取码云上传头像请求

java
POST https://gitee.com/profile/upload_portrait_with_base64 HTTP/1.1
Host: gitee.com
Connection: keep-alive
Content-Length: 107389
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
Accept: */*
X-CSRF-Token: 6ROfZGr4Y7Qx8td1TuKCnrG8gbODLCSUqUBZSw2b+ac=
X-Requested-With: XMLHttpRequest
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: https://gitee.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://gitee.com/HGtz2222
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: oschina_new_user=false; user_locale=zh-CN; yp_riddler_id=1ce4a551-a160-4
avatar=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAPgAAAD4CAYAAADB0Ss
实际的抓包结果⽐较⻓,此处没有全部贴出.
- multipart/form-data
java
POST https://v.bitedu.vip/tms/oss/upload/file HTTP/1.1
Host: v.bitedu.vip
Connection: keep-alive
Content-Length: 293252
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjFiYThjMDM5L
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8d5Rp4eJgrUSS3
Accept: */*
Origin: https://v.bitedu.vip
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://v.bitedu.vip/personInf/student?userId=665
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: rememberMe=true; username=18691491410; Admin-Token=eyJhbGciOiJIUzUxMiJ
------WebKitFormBoundary8d5Rp4eJgrUSS3wT
Content-Disposition: form-data; name="file"; filename="
李星亚
Java
开发⼯程师
.pdf"
Content-Type: application/pdf
%PDF-1.7
%³
1 0 obj
<</Names <</Dests 4 0 R>> /Outlines 5 0 R /Pages 2 0 R /Type /Catalog>>
endobj
3 0 obj
<</Author ( N v~N) /Comments () /Company () /CreationDate (D:20201122145133+06'
endobj
13 0 obj
<</AIS false /BM /Normal /CA 1 /Type /ExtGState /ca 1>>
endobj
- application/json

HTTP响应详解
认识"状态码"(statuscode)
状态码表⽰访问⼀个⻚⾯的结果.(是访问成功,还是失败,还是其他的⼀些情况...).

以下为常见 的状态码.
200OK
这是⼀个最常⻅的状态码,表⽰访问成功. 抓包抓到的⼤部分结果都是200 例如访问搜狗主页
java
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; do
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
......
注意:等待的过程就用 -表示

注意:在抓包观察响应数据的时候,可能会看到压缩之后的数据,形如:

⽹络传输中"带宽"是⼀个稀缺资源,为了传输效率更⾼往往会对数据进⾏压缩.
点击Fiddler中的

即可进行解压缩,看到原始的内容.
404NotFound
没有找到资源. 浏览器输入⼀个URL,目的就是为了访问对方服务器上的⼀个资源.如果这个URL标识的资源不存在, 那么就会出现404 例如,在浏览器中输⼊ www.sogou.com/index.html ,此时就在尝试访问sogou上的 /index.html 这个资源. 如果输⼊正确,则可以正确访问到.但是如果输⼊错误,比如 会看到404这样的响应
403Forbidden
表⽰访问被拒绝.有的⻚⾯通常需要⽤⼾具有⼀定的权限才能访问(登陆后才能访问).如果⽤⼾没有登陆 直接访问,就容易见到403.
例如:查看码云的私有仓库,如果不登陆,就会出现403.参考链接: https://gitee.com/HGtz2222/blog_python
405MethodNotAllowed
前⾯我们已经学习了HTTP中所⽀持的方法,有GET,POST,PUT,DELETE等. 但是对⽅的服务器不⼀定都⽀持所有的方法(或者不允许用户使用⼀些其他的方法). 这种情况我们后⾯学习了Servlet再演⽰.
500Internal Server Error
服务器出现内部错误.⼀般是服务器的代码执行过程中遇到了⼀些特殊情况(服务器异常崩溃)会产⽣这 个状态码. 咱们平时常用的网站很少会出现500(但是偶尔也能看到). 这种情况我们后面学习了Servlet再演演示
504GatewayTimeout
当服务器负载比较⼤的时候,服务器处理单条请求的时候消耗的时间就会很⻓,就可能会导致出现超时 的情况. 这种情况在双⼗⼀等"秒杀"场景中容易出现,平时不太容易见到.
服务器资源紧张常见
302Movetemporarily
临时重定向.
理解"重定向" 就相当于⼿机号码中的"呼叫转移"功能.
比如我本来的⼿机号是186-1234-5678,后来换了个新号码135-1234-5678,那么不需要让我的朋友知 道新号码,
只要我去办理⼀个呼叫转移业务,其他⼈拨打186-1234-5678,就会⾃动转移到135-1234-5678上.
在登陆页面中经常会见到302.⽤于实现登陆成功后⾃动跳转到主⻚. 响应报⽂的header部分会包含⼀个Location字段,表⽰要跳转到哪个页⾯. 例如:码云的登陆⻚⾯https://gitee.com/login 抓包看到的响应结果

前端网络请求演进史
1. jQuery.ajax(2010 年,江湖地位无人能撼)
javascript
$.ajax({
method: 'get',
url: 'xxx',
success: function(body) { // 回调地狱的始作俑者
console.log(body);
}
});
- 优点:跨浏览器兼容极好,当时 IE6/7 横行,jQuery 自动处理所有兼容性坑
- 缺点:回调地狱,success/error/complete 三件套,代码嵌套层出不穷
- 地位:2010-2015 绝对统治者,所有网站都在用
2. Angular HttpClient(2018 年,类型安全的王者)
javascript
this.http.get<User[]>('api/users')
.pipe(map(users => users.filter(u => u.active)))
.subscribe(users => this.users = users);
- 核心:基于 RxJS Observable(可观察流),不是 Promise
- 优势:类型推断完美(TypeScript 友好),链式操作丝滑
- 缺点:学习成本高,RxJS 陡峭的学习曲线
- 适用:企业级 Angular 项目标配
3. Axios(2015 年,Vue/React 生态霸主)
javascript
axios.get('xxx').then(response => {
console.log(response.data); // 自动解析 JSON
});
- 杀手锏 :
- 拦截器:请求前/后统一处理(加 token、处理错误)
- 自动转换:自动 JSON.stringify/parse
- 取消请求:支持 AbortController
- 生态:Vue 官方推荐,React 社区也爱用
- 现状:2024 年依然是主流选择
4. Fetch API(2017 年,浏览器原生标准)
javascript
fetch('xxx')
.then(response => response.json()) // 手动解析 JSON
.then(data => console.log(data));
- 优点:原生,无需额外库,现代语法
- 缺点 :
- 不自动解析 JSON(要手动 .json())
- 不自动处理错误(4xx/5xx 也算成功)
- 取消请求需要 AbortController(有点麻烦)
- 现状:适合简单场景,复杂项目还是用 Axios
5. XMLHttpRequest(始祖,永远不会完全淘汰)
JavaScript
javascript
const xhr = new XMLHttpRequest();
xhr.open('GET', 'xxx');
xhr.onload = function() {
console.log(xhr.responseText);
};
xhr.send();
- 地位:所有现代库的底层实现,浏览器原生最底层 API
- 特点:回调式,原始粗暴,但最稳定
通过ajax构造HTTP请求
前端⻆度,除了浏览器地址栏能构造GET请求,form表单能构造GET和POST之外,还可以通过 ajax 的⽅式来构造HTTP请求.并且功能更强大
ajax 全称AsynchronousJavascriptAndXML,是2005年提出的⼀种JavaScript给服务器发送 HTTP请求的方式.
特点是可以不需要刷新页面/页面跳转就能进行数据传输.
在JavaScript 中可以通过ajax的方式构造HTTP请求
发送GET请求

javascript
<!--
引⼊
jquery -->
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<script>
$.ajax({
type: 'get',
url: 'https://www.sogou.com?studentName=zhangsan',
success: function(data) {
}
});
// 此处success 就声明了⼀个回调函数, 就会在服务器响应返回到浏览器的时候触发该回调
// 正是此处的 回调体现 "异步"
// data 则是响应的正⽂部分.
console.log("当服务器返回的响应到达浏览器之后, 浏览器触发该回调,们
console.log("浏览器⽴即往下执⾏后续代码");
</script>
注意:如果把send中的地址改成其他服务器的地址(⽐如http://www.sogou.com/index.html这种), 大概率是会出错的.
这个错误是因为ajax默认不能"跨域",也就是"百度下⾯的html中的ajax不能访问搜狗的内容".这 样的设定也是完全合理的. 如果想要强⾏进⾏跨域,则需要服务器进⾏配合,在服务器的响应中"允许跨域"才可以. 咱们的⽰例服务器 42.192.83.143:8080/AjaxMockServer/info 进行了允许跨域设置,因 此我们的⻚⾯才能访问到其中的数据.
关于跨域这个话题,此处不深⼊讨论. 浏览器和服务器交互过程(引⼊ajax后)

在我们当前的例⼦中,test.html是通过本地⽂件的⽅式打开的,这个环节不涉及HTTP交互. 后⾯我们把test.html放到Tomcat上,就会产⽣上⾯的效果了
发送POST请求
对于POST请求,需要设置body的内容 1. 先使⽤setRequestHeader设置Content-Type 2. 再通过send的参数设置body内容.
发送application/x-www-form-urlencoded数据(数据格式同form的post)
javascript
<!--
引⼊
jquery -->
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<script>
$.ajax({
type: 'post',
url: 'https://www.sogou.com',
contentType: 'application/x-www-form-urlencoded
}
});
',
data: 'studentName=zhangsan',
success: function(data) {
// data 则是响应的正⽂部分.
console.log("当服务器返回的响应到达浏览器之后, 浏览器触发该回调, 通知到咱们
console.log("浏览器⽴即往下执⾏后续代码");
</script>
发送application/json数据:
javascript
<!-- 引⼊ jquery -->
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<script>
$.ajax({
type: 'post', url: 'https://www.sogou.com', contentType: 'application/json ',} });
data: '{ name: "zhangsan" }',
success: function(data) {
// data 则是响应的正⽂部分.
console.log("当服务器返回的响应到达浏览器之后, 浏览器触发该回调, 通知到咱们
console.log("浏览器⽴即往下执⾏后续代码");
</script>
通过Javasocket构造HTTP请求
所谓的"发送HTTP请求",本质上就是按照HTTP的格式往TCPSocket中写⼊⼀个字符串. 所谓的"接受HTTP响应",本质上就是从TCPSocket中读取⼀个字符串,再按照HTTP的格式来解析. 我们基于Socket的知识,完全可以构造出⼀个简单的HTTP客⼾端程序,⽤来发送各种类型的HTTP请求
使⽤Java构造的HTTP客⼾端不再有"跨域"限制了,此时也可以来获取其他服务器的数据了
引入https ,SSL 与TLS
运行商劫:持:

