HTTP 深水区:重定向、状态码与 GET/POST 的传参之路
我的github:(https://github.com/xcx55/ubuntu-linux-project)
感谢各位大佬参观我的github!!
源笔记:http6(26-9-13)、临时重定向和永久重定向(26-9-14)、http7(26-9-15)、为什么写服务端要遵循返回码的准确、矛盾1、http重要内容指引
报文格式认识完,HTTP 才算过了笔试。真正的深水区是这些:点一个按钮怎么就跳页了?404 是谁画的?表单数据是怎么钻进服务器的?一个 URL 为什么既能是文件也能是服务? 这一篇把 3xx 重定向、状态码的契约、GET/POST 传参和路由全部串起来。
一、先破一个题:点击按钮跳转页面,是怎么完成的?
前提认知:前端代码本身是可以向对应服务器发起请求的------前端严格意义上是后端文件的映射多叉树,前端代码可以直接发起请求!
所以"点击跳转"的完整链条是:前端检测到点击 → 发起 HTTP 请求 → 服务端返回报文 → 前端检测到报文解析,依据状态码进行前端代码的再次请求------修改显示的 URL,也是渲染出来的一部分。
二、3xx 重定向:临时与永久的分界线
重定向标准:自动从一个页面跳转到另一个页面,就是重定向。 (提醒一句:还有一个"重定向"是文件系统的------改变进程 struct file* 数组下标指针,那是 Linux 章的老朋友,同名不同物。)
重定向分为两种:临时重定向(302/307)和永久重定向(301) 。核心区别就一句话:信息不同。
永久重定向:浏览器替你记一辈子
浏览器有一个机制:每一次得到永久重定向,就会在本地配置文件里以 key:value 的方式写入 ------k: 你第一次访问的地址,v: 带回来的真正地址。后面再次访问,不会先走网络连接,而是直接本地判断,得到真正要访问的地址。一次通信,终身有效。
临时重定向:每次都问一遍
临时重定向不会写本地文件 ------每次都是直接去看一眼:服务端发状态码回来,判断去 response 里面 Location 报头的地址去访问。跳一次问一次。
典型场景
- 临时重定向用得最多:登录之后,直接跳转到首页;
- 永久重定向我们用得比较少:典型如网站换域名,老地址永久搬家;
- 一个常见组合拳:一般没有对应文件的,给出 404;要自定义 404 页面,就返回 3xx,Location 指向自己的资源(可以是本站路径,也可以是全新主机+URL)。
三、状态码:浏览器是按状态码"硬编码"办事的
到这里必须回答一个根本问题:为什么我们写服务端要遵循返回码的准确?
因为浏览器的 JavaScript 逻辑是写死的:
- 3xx 开头 → 去读取 response 的 Location,发起再次请求(永久重定向同时写本地文件);
- 4xx 开头 → 加载本地的 404 NOT FOUND 页面;
- 200 → 读取主体(body),浏览器渲染。注意:状态码 200 并不是直接渲染,还得有 body!没有 body 就不渲染。
也就是说,返回的状态码决定了客户端对报文怎么处理 。你要是乱返回------明明 404 偏回个 200------浏览器就按 200 的逻辑走,页面直接渲染不出来。浏览器客户端是好的,坏的一般是服务端。
那什么时候可以不遵守?客户端和服务端都是自己写的时候------自己定的协议自己认就行。但只要对面是浏览器,就得按浏览器的合同来。
补充一个实战细节(矛盾1 的化解):客户端发起的请求,URL 指向外站怎么办?服务端直接驳回,返回 404;一般发现是图床的文件,就发起 3xx 临时重定向,让浏览器去图床那台主机拿------反正底层再建一个 TCP 连接就是了。
四、一个网页有多个请求:从短连接到长连接
浏览器怎么显示图片?前端代码可以发出多个请求 :先请求第一批网页(HTML),渲染完成后再运行到请求代码,再一次发起请求加载文件图片。
- 以前 HTTP 基于 TCP 是短连接:一个网页图片少,多来几次短连接还能接受;
- 但随着图片变多,HTTP/1.0 就愈发不能接受了------于是推出 HTTP/1.1;
- 1.1 的做法:请求报文里有 Connection 报头,服务端用 map 方式查有没有这个属性------有,就保持长连接。至于默认长连接短连接的本质,还得学 TCP 底层(后面的笔记补上了这个坑)。
对应的工程细节:一个网页可能有多个请求,浏览器是以多线程(线程池)方式向服务端发起请求的 。读取数据(代码、视频、图片)最好用 vector------因为文件流读到 \0 会提前截断,二进制方式打开 + 查操作系统要文件大小,才不会被 \0 打扰。
五、Content-Type:服务端怎么知道自己发的是什么
response 里还有一个关键报头:Content-Type。
- 服务端怎么知道自己发送的资源是什么格式的?------通过资源后缀(.html/.jpg/.mp4);
- 后缀从哪来?客户端的 URL 会告诉服务端;
- 服务端找到文件后,按后缀和 type 的转换对照表填 Content-Type 返回------客户端拿到才知道怎么渲染。
六、GET/POST:两条传参之路
之前学的所有东西都是静态资源 (图片、视频、网页文件)。那怎么给服务器提交数据?这就是动态的参数------HTTP 常见的请求方法就是干这个的。
GET:参数拼在 URL 里
url?键值对&键值对&......
GET 传参是和 URL 一起传的,直接可见。而且 GET 传参会进行回显------URL 回显是浏览器默认做的,方便我们,但也有危险(密码裸奔在地址栏里)。
POST:参数藏在正文里
POST 专一化传参,但通过正文提参------方法和状态码有类似的地位功能:一个是报文的"动作",一个是报文的"判决"。
最常见的一种方式是表单 :输入框就是表单渲染的结果,提交表单时,浏览器把 name=value 按约定的编码塞进请求正文,Content-Type 告诉服务端怎么解。所以说:浏览器把数据给到服务器的最常见方式,就是表单。
七、URL 的两种视角:资源路由和功能路由
到这里 HTTP 最有意思的一层就出来了:URL 可以是具体资源申请,也可以是动态资源申请------资源路由和功能路由!(功能服务花样多,还可以有代理服务。)
那"服务"是啥?从这里切入:
- 服务就是函数:参数以 k、v 传进来,接入数据库;
- 服务端把函数以
wwroot+url作为 map 的键值存储 ,函数本体用 function 类型擦除包装(包装类里面是函数指针类型变量等等),Function 作为右值塞进去; - 每一次请求来袭,服务端判断:到底是要请求静态资源,还是调用服务函数------是资源就返回文件,是函数就把传来的数据分割、调用、返回结果;
- 所以 POST 方法还是 GET 方法,区别只是 URL 的判断和参数传递位置的不同;
- 注册的函数可以跨平台跨主机操作,只要 TCP 连接上即可------图床就是这么玩的。
总结
- 前端本身能发请求,跳转 = 状态码驱动的"前端再次请求";
- 临时重定向 每次看 Location(302),永久重定向浏览器记本地文件终身免问(301);自定义 404 = 3xx + 自己的资源;
- 状态码是浏览器硬编码的合同:3xx 读 Location、4xx 本地 404 页、200 必须有 body 才渲染------服务端返回码必须准确;
- 一个网页多个请求 → 短连接撑不住 → HTTP/1.1 的 Connection 报头支持长连接;
- Content-Type 靠资源后缀查对照表;
- GET 参数在 URL(回显、危险),POST 参数在正文,表单是最常见的提交方式;
- URL 的两种视角:资源路由和功能路由------服务就是函数,map 键值 + function 类型擦除完成注册,静态和动态在服务端一刀分开。
HTTP 还剩最后两块硬骨头:HTTPS 为什么安全、登录状态是怎么"记住你"的。下一篇收官,顺带推开 MySQL 的大门。