HTTP协议与Apache服务

📅 2026/7/24 18:03:03
HTTP协议与Apache服务
HTTP协议与Apache服务写在前面今天把 HTTP 协议和 Apache 服务从前到后撸了一遍。这篇博客用说人话的方式把知识点串起来尽量做到看完能懂、懂了能记住。一、HTTP 协议 — 互联网的快递系统1.1 一个请求的完整旅程你有没有想过在浏览器敲下www.baidu.com回车后到底发生了什么你(浏览器) → DNS问路 → 找到服务器IP → 发请求 → 服务器处理 → 返回响应 → 浏览器渲染整个过程跟网购下单一模一样DNS解析 查地图你知道你要去百度大厦但得先知道它在哪条街几号TCP连接 打通电话双方确认喂能听到吗发送请求 告诉客服我要这个商品服务器处理 客服去仓库拿货返回响应 快递送到你手上渲染页面 拆快递、摆好1.2 HTTP 的性格 — 没记性的协议HTTP 有个很重要的特点叫无状态。什么意思就是服务器像个金鱼——7秒记忆。你第一次访问网站服务器不认识你你第二次访问服务器还是不认识你。每个请求都是独立的服务器不会记住你刚刚来过。 那问题来了淘宝怎么知道是你登录的购物车怎么记住你加的商品这就引出了三个解决方案我们一个个说。1.3 没记性的三种解决方案Cookie — 贴在你脑门上的小纸条服务器给你一张小纸条Set-Cookie上面写着你的身份信息。你每次访问都把纸条贴脑门上递给服务器请求头里的Cookie。缺点纸条空间有限4KB而且贴脑门上不安全别人能看到。Session — 会员卡制度服务器给你一张会员卡session_id卡号记在你那会员信息存在服务器那。你每次来报卡号服务器去后台查你的信息。比Cookie安全因为详细信息存在服务器里。缺点服务器多了怎么办你有三台服务器会员信息只存在第一台第二台不认识你。这就是 session 共享问题需要额外手段解决redis共享、session复制等。JWT — 自带简历的求职者JWTJSON Web Token是个很巧妙的方案。服务器把你的信息加密编码成一个很长的字符串给你你每次访问把这个字符串带上就行。JWT结构xxxxx.yyyyy.zzzzz 头部.载荷.签名这就像你去面试自己带简历面试官不用去查你的档案直接看简历就行了。服务端不需要存任何会话信息这在分布式系统里特别好用。三者的简单对比方案核心逻辑一句话类比Cookie客户端存小数据脑门上贴纸条Session服务端存数据客户存ID会员卡后台档案JWT数据全在客户端加密签名自带简历去面试1.4 从 0.9 到 3 — HTTP 版本成长史HTTP/0.9 (1991)— 原始人版只能发 GET 请求只传纯文本请求完就断渣男行为HTTP/1.0 (1996)— 儿童版多了 POST、HEAD有了状态码200、404这些有了 Header 头能传图片了多亏 JPEG 1992年发明HTTP/1.1 (1999)— 成年版至今主流持久连接不用每次请求都重新建立TCP连接省了三次握手的开销多了 PUT、DELETEHost头强制一个服务器可以托管多个域名虚拟主机的基础分块传输大文件可以切块发这里有个经典面试题HTTP/1.1 的持久连接和管道有什么区别持久连接多个请求可以共用一条TCP连接但得一个一个来响应完才发下一个管道可以连续发请求不用等前一个响应回来但响应还是得按顺序回来队头阻塞HTTP/2 (2015)— 青年版二进制协议不再是纯文本多路复用可以同时发多个请求不受队头阻塞的限制头部压缩减少重复数据传输服务端推送服务器可以主动给客户端塞资源HTTP/3 (2022)— 未来版基于 QUIC 协议底层用 UDP 而不是 TCP连接建立更快0-RTT解决了 TCP 层面的队头阻塞二、Url 的结构 — 地址的五个要素http://www.magedu.com:8080/images/logo.jpg拿收快递来类比http://— 用什么交通工具快递/专车/飞机www.magedu.com— 哪个小区:8080— 哪个门不写就是默认大门HTTP默认80HTTPS默认443/images/logo.jpg— 几栋几号房问号后面的查询参数 (?keyvalue) — 给收件人的备注信息URI vs URL vs URNURI是总称标识符URL是用地址定位你家的门牌号URN是用名称定位你的身份证号。实践中我们基本只用URL。三、请求和响应 — 一问一答的对话模式请求报文的格式GET /index.html HTTP/1.1 Host: www.example.com User-Agent: Chrome/... ...其他头部 ​ 请求体POST时才有响应报文的格式HTTP/1.1 200 OK Content-Type: text/html ...其他头部 ​ !DOCTYPE html html.../html状态码 — 服务器的脸色范围含义经典代表1xx还在处理别急101 切换协议WebSocket2xx搞定 ✅200 成功3xx挪地方了 301 永久搬家302 临时串门304 你缓存有不发了4xx你的锅 ❌403 不让进404 没这东西405 方法不允许5xx我的锅 500 我崩了502 上游崩了504 上游超时了记忆口诀1等2成3重4错5挂四、静态 vs 动态资源举个栗子你开了一家打印店静态资源 墙上挂好的打印好的成品海报谁来都是一样的直接拿走就行服务器直接从磁盘返回文件可以提前准备好很多份缓存动态资源 客户说帮我做个带照片的生日贺卡每个客户的要求不一样得现做服务器调用PHP/Python代码生成每次做出来的都不一样前端三件套就是做这些资源的工具HTML 毛坯房结构承重墙、门窗CSS 装修风格墙面颜色、地板材质JavaScript 智能家居能交互的功能五、Apache 工作模式 — 一家餐厅的三种运营风格Apache 有三种工作模式MPM底层对应不同的 IO 模型。prefork — 家庭小作坊一个人进程服务一桌客人客人没走就不能去服务其他人。优点稳定、不出错。PHP必须用这种模式。缺点开太多人进程太占资源人多的时候忙不过来。worker — 有服务员的小餐厅厨房里几个大厨进程每个大厨带几个服务员线程一个服务员服务一桌客人。优点比 prefork 省资源能接待更多客人。缺点线程之间会互相影响一个服务员犯错可能影响整个厨房。event — 现代智能餐厅每个服务员可以同时服务好几桌客人客人点完菜就去服务别人菜好了再送过去事件驱动。优点并发能力最强Apache 2.4 默认模式。缺点跟某些模块不兼容。三种模式的本质区别其实对应着前面讲的 IO 模型prefork 阻塞 IO一个进程死等一个请求worker 多线程的阻塞 IOevent 多路复用 IOepoll六、Apache PHP 的搭桥方案Apache 本身只是个文件传输员它不认识 PHP 代码。要让 Apache 能处理 PHP 动态页面有两种搭桥方式方案一模块加载 — 合体变身把 PHP 处理器直接装进 Apache 体内合二为一。apt install php安装完你会发现Apache 自动从 event 模式切换成了 prefork 模式——因为 PHP 模块只兼容 prefork。优点速度快不用来回传数据缺点改了 PHP 就得重启 Apache而且不能分开扩容方案二FastCGI/php-fpm — 隔壁老王Apache 和 PHP-FPM 各干各的Apache 收到 PHP 请求时通过代理转发给隔壁的 PHP-FPM 处理处理完再拿回来。FilesMatch \.php$ SetHandler proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost /FilesMatch优点两者可以分开部署、分开扩容PHP 改完不用重启 ApacheApache 可以继续用 event 模式更高效缺点多了一层网络通信稍微慢一点CGI vs FastCGICGI 每次请求都新开一个 PHP 进程用完就丢FastCGI 把 PHP 进程常驻内存用完了还留着等下一个请求。就像雇佣临时工 vs 雇佣全职员工——临时工干完活就走下次再招又要重新培训全职员工一直在岗来了活直接干。七、虚拟主机 — 一房多住的魔法一个 Apache 实例怎么同时服务多个网站有三种方式基于端口—— www.a.com:80 是A站www.a.com:8080 是B站基于IP—— 192.168.1.10是A站192.168.1.11是B站基于域名—— 服务器所有站都监听*:80根据 HTTP 请求头里的Host字段来区分生产环境99%用基于域名的方式。配置如下VirtualHost *:80 DocumentRoot /var/www/site_a/ ServerName www.a.com /VirtualHost ​ VirtualHost *:80 DocumentRoot /var/www/site_b/ ServerName www.b.com /VirtualHost八、IO 模型 — 计算机的等 vs 做哲学这可能是整个文档里最难啃的一块我尽量用大白话说明白。8.1 四个基础概念先搞清楚两组概念很多人面试就挂在这同步 vs 异步关注的是消息通知的方式同步你自己去盯着结果结果出来了算你的异步你告诉别人结果出来了通知我结果出来了别人喊你阻塞 vs 非阻塞关注的是调用者能不能干别的事阻塞调用后啥也不干干等非阻塞调用后可以先干别的时不时回来瞅一眼类比你去奶茶店买奶茶同步阻塞站在柜台前死等哪儿也不去同步非阻塞做杯奶茶要5分钟你每30秒来问一次好了没轮询异步阻塞你拿号在店里坐着但啥也不干就盯着叫号屏异步非阻塞拿号逛街去了手机震动说您的奶茶好了才回来拿8.2 五种 IO 模型从差到好排队假设要从网络读取数据整个过程分两步等待数据就绪快递从商家发出在路上了数据从内核拷贝到用户空间快递到驿站了你去取回来不同模型在这两阶段的处理方式不同① 阻塞 IO — 一根筋你在门口等快递哪儿也不去快递没到你就在那站着。快递到了你自己搬进屋。第1阶段阻塞等待干等快递第2阶段阻塞拷贝自己搬进屋特点实现简单但一个人只能等一个快递一个线程只能处理一个连接② 非阻塞 IO — 来回跑你时不时跑门口看一眼快递没到就回去刷手机过会儿再来看。快递到了你自己搬进屋。第1阶段轮询检查时不时看一眼第2阶段阻塞拷贝自己搬进屋特点CPU浪费在轮询上不停跑去门口看数据拷贝阶段依然阻塞③ 多路复用 IO — 有个前台帮你盯着你请了个前台select/epoll前台帮你盯着所有快递。哪个快递到了前台告诉你你再自己去搬进屋。第1阶段前台帮你等不消耗你的时间第2阶段你自己搬阻塞拷贝特点一个前台可以盯几千个快递高并发但每次只能搬一个仍然是阻塞拷贝代表Nginx、Redis、Netty这就是Nginx为什么能处理高并发的秘密——它用一个进程前台盯着成千上万个连接哪个有动静就处理哪个不像 Apache prefork 那样一个连接开一个进程。④ 信号驱动 IO — 快递到了喊你你跟快递员说到了打我电话然后该干嘛干嘛。快递到了电话响了你去门口自己搬进屋。第1阶段信号通知不阻塞第2阶段阻塞拷贝自己搬特点通知及时但实际场景用得少⑤ 异步 IO — 全程不用你动手你跟快递员说到了直接帮我搬进屋放好快递到了他自己搬进屋放好然后发条微信告诉你已放好。自始至终你没动过。第1阶段不阻塞第2阶段不阻塞内核帮你搬完了才通知你特点理论上最好但 Linux 下支持不完善。Windows 的 IOCP 是真正的异步 IO。8.3 select/poll/epoll 的区别必考面试题特性selectpollepoll文件描述符上限1024无限制无限制通知机制全量扫描全量扫描仅通知就绪的效率连接数越多越慢同 select连接多时依然快平台通用通用Linux 独有一句话总结select 和 poll 是把所有人叫起来问谁到了epoll 是谁到了谁举手所以 epoll 在大量连接时效率高得多。8.4 零拷贝 — 不走弯路的数据搬运传统的数据传输需要数据在 磁盘 → 内核缓冲区 → 用户缓冲区 → 内核缓冲区 → 网卡 之间来回拷贝效率低。零拷贝技术就是减少这些不必要的拷贝mmapwrite共享内存省掉一次内核到用户的拷贝sendfile数据直接在内核空间从磁盘到网卡完全不经过用户空间splice在两个文件描述符之间直接搬运数据九、LAMP 全家桶 — 搭建一个真正的网站LAMP Linux Apache MySQL PHP打个比方一个动态网站的工作流程像这样你(浏览器) → 到Apache前台问有没有东西卖 Apache看你问的是PHP动态页面 → 叫来PHP小哥帮你处理 PHP小哥说我得查查数据库 → 跑去MySQL仓库翻数据 MySQL找到数据给PHP小哥 → PHP小哥拼装好给Apache Apache把结果交给你(浏览器)踩坑提醒localhost vs 127.0.0.1这俩看起来一样但在 MySQL 里天差地别。# 这样能连上 mysql -uroot -hlocalhost # 这样连不上 mysql -uroot -h127.0.0.1原因localhost→ 走 UNIX socket效率高不走网络栈127.0.0.1→ 走 TCP/IP经过网络协议栈MySQL 中rootlocalhost和root127.0.0.1是两个不同的用户Ubuntu 默认 root 的认证插件是auth_socket依赖Linux系统用户身份验证要改成mysql_native_password才能用密码和远程登录ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 密码;PHP 加速 — OPcachePHP 是解释型语言每次请求都要把 PHP 文件从头到尾读一遍、解析一遍就像每次做饭都要重新看菜谱从头学起。OPcache就像把菜谱背下来记在脑子里下次做同样菜直接动手不用再看菜谱了把预编译的字节码存到共享内存。写在最后这份文档量很大从 HTTP 协议的历史演进到 Apache 的实战配置从五层 IO 模型到底层零拷贝技术基本覆盖了 Web 服务端开发的整个知识链条。几个必须要记住的核心要点HTTP 是无状态的——Cookie/Session/JWT 是三种解决方案Apache 三种 MPM——prefork(稳)、worker(线程)、event(高性能)Apache PHP 的两种方式——模块加载 vs FastCGI虚拟主机按域名区分最常用五种 IO 模型——阻塞 非阻塞 多路复用 信号驱动 异步localhost vs 127.0.0.1——在数据库层面完全是两回事希望这篇博客能帮你从背命令到真懂了~