动态 Web 是什么、开发环境怎么搭¶
这一章讲两件事: 第一,你在浏览器里看到的网页,背后到底发生了什么样的「问答」, 为什么有的网页每次答得一样、有的每次都不一样;第二,怎样在你自己的电脑上搭出这套问答所需的全部角色, 让浏览器能问、本机能答。 读完你会拿到全书的地基——后面二十章写的每一行代码,都跑在这套问答机制上。 不需要任何基础,遇到的缩写都在当场解释。
1. 顶层全景:一次网页访问,就是一次问答¶
把整章压成一张图:
浏览器(客户) ──发问──▶ 服务器 ──▶ 磁盘上的文件? ──▶ 原样发回 (静态页)
│
└─▶ 里面是 PHP? ──▶ PHP 解释器执行
│ 需要数据? ──▶ MySQL 查库
▼
拼好的 HTML ──▶ 发回浏览器
图说:静态页是「从磁盘取文件寄出」;动态页中间多两道工序——先算(PHP),再查(MySQL)。
这张图里的三个新角色——服务器、PHP、MySQL——下面逐个讲。这里先记住一句话: 网页不是存在服务器上等着被取走的「成品」,而是服务器现场「答」出来的。 答的过程可以很简单(把磁盘上的文件原样寄回),也可以很复杂(先执行一段程序、查一次数据库,再拼出结果)。 全书的主题就是把「答」做复杂——做得每次都不一样、因人而异、因时而异。
2. 从一次具体的访问走一遍(主线例子)¶
挑一个最普通的动作:在浏览器地址栏输入 http://server.com,敲回车。
原书把这次访问拆成了七步,我们照着走一遍,每一步旁边有具体的状态18:
- 浏览器拿到这串网址,先要查出
server.com这台机器在网络上的「门牌号」。 网址是人看的名字,机器之间认的是 IP 地址(一串数字编号)。 浏览器会去问另一个网络服务——DNS(域名系统,Domain Name System 的缩写)——把名字换成地址19。 - 浏览器拿着地址,向那台机器发一个「请求」:把你的主页给我。 这个请求走的规矩叫 HTTP——它只规定两件事:请求怎么问、回答怎么答20。
- 请求穿过互联网,到达 server.com 的 web 服务器(一台守在门口、专门接请求的软件)。 服务器没事干的时候就在「听」,听到请求就处理21。
- 服务器从自己的磁盘上找到主页文件,寄回给浏览器。
- 浏览器把收到的 HTML(超文本标记语言,描述网页结构的那套标签)画出来——你看到了页面。
注意一个容易忽略的细节:上面这套流程,页面里每一样「附件」都要各走一遍。 一张图、一段视频、一个样式表,都是浏览器解析 HTML 时发现「还缺这个」, 再各发一次请求取回来的22。所以你打开一个网页,底下可能是几十次问答的叠加。
轮到动态页:中间多出来的五道工序¶
现在换成动态场景:你点击页面上一件雨衣的图片,想看清它的细节。
前四步和上面一样——查地址、发请求、到达服务器、取出文件。 从第 5 步开始分叉,原书列出的完整链条是23:
- 服务器发现取出的文件是个
.php文件,把它交给 PHP 解释器—— 一个专门逐行执行 PHP 程序的软件24。 - PHP 代码里写着「去数据库查这件雨衣」:SQL 语句(数据库的查询语言)被转交给 MySQL——一个独立的数据库程序,也在同一台机器上跑着。
- MySQL 查完,把雨衣的价格、库存、颜色这些行返回给 PHP。
- PHP 把这些数据包进 HTML 模板(「包进」就是拼字符串:标签是固定的,数据是刚查出来的),交给服务器。
- 服务器把这份新鲜出炉的 HTML 寄回浏览器,浏览器画出来。
对比一下:静态页在第 4 步就结束了;动态页多走的 5~8 步,就是「PHP」和「MySQL」这两个名字的全部含义。 PHP 负责「算」——决定这一页上放什么;MySQL 负责「存」——记住所有该被放进页面的数据。 这也解释了书名的组合为什么是这样:PHP 和 MySQL 是这套问答里后端的两个分工。
3. 五个角色各管什么¶
第一章后半部分把动态网页的五个技术角色各用一节过了一遍。这一节按原书的讲法接住它们。
3.1 PHP:在服务器上「算」的那道工序¶
PHP 是一门运行在服务器上的编程语言。它的用法有一个非常具体的特点:
直接写在 HTML 中间,用一对标签圈出来。<?php 告诉服务器「从这里往下是程序,先执行」,
?> 告诉它「到这里为止,剩下的照旧发出去」25。
原书给的第一个例子只有一行:
走一遍:服务器执行 date("l") 拿到服务器本机时间里的星期几(比如 Wednesday),
拼进字符串;标签外面的那句英文原样不动。浏览器最终收到的 HTML 是:
对浏览器来说,这份 HTML 和一个手写的静态文件毫无区别——它不知道也不在乎中间的星期三是怎么来的。 这就是「动态」的确切意思:浏览器收到的每次都是平平无奇的 HTML, 但 HTML 的内容是请求到达的那一刻才决定出来的。
顺带交代一个术语:在 web 语境里,「客户端」(client)指发起请求的一方——浏览器和它所在的电脑; 「服务器端」(server)指应答的一方。所以常说「PHP 是服务器端语言」, 意思是它运行在应答那一头,用户看不见它的代码,只看得见它算完的结果26。
3.2 MySQL:用「像英语的命令」管数据¶
光会动态地拼 HTML 还不够——「这件雨衣多少钱」这样的数据总得存在某个地方。 早年的网站把数据存在普通文本文件里,原书列了这种做法的两个死穴: 多个访客同时写入时文件容易写坏;文件大到一定程度后,合并、搜索都慢得没法用27。
数据库就是为解决这两个死穴而生的:它专门管「很多人同时读写一堆数据」这件事。 MySQL 是其中装得最广的一个,免费的,用一套像英语的命令(叫 SQL)操作。
它的结构用原书的比方最清楚:一个 MySQL 数据库像一个 Excel 文件,里面的表(table)像这个文件里的工作表;
表由行和列组成,列有名字和类型28。比如一张 users 表存用户,加一行用户是这样一条命令:
「INSERT INTO」就是「插入到……里面」——SQL 的英语味就是这么直给。
查人也一样:SELECT surname,firstname FROM users WHERE email='jsmith@mysite.com';
大意是「从 users 表里选出姓氏和名字,条件是邮箱等于这一串」29。
这两条的细节(为什么值要加引号、条件怎么写)第六章和第八章再展开,这里只需要建立印象:
SQL 说的是「要什么」,不管「怎么找」——怎么找是 MySQL 内部的事。
3.3 JavaScript:在浏览器里「演」的那道工序¶
JavaScript 运行在客户端——它是唯一一个跑在用户浏览器里的角色,所以它能做的事 PHP 做不到: 不经过服务器,当场改动页面上任何一个元素。鼠标悬停弹提示、拖放、无刷新更新局部内容,都是它在干活30。
它和 Java 的名字相似纯属 1995 年诞生时的营销巧合,两门语言没有关系—— 书里特意点破,因为初学者常被这个名字误导31。
JavaScript 还有一个身份值得记住:它是「异步通信」的主角。 异步通信的意思是:页面已经显示完了,JavaScript 还在后台偷偷和服务器继续问答—— 你在注册 Gmail 时输入用户名,它当场告诉你要不要换一个,页面却没有整个刷新,就是这个机制32。 这个机制第 17 章细讲,第一章只负责让你知道它存在、并且需要 JavaScript 在场。
3.4 CSS:管「长什么样」¶
CSS(层叠样式表)管的是呈现:颜色、间距、字体、布局。 书里有句话点出了 CSS 近年的变化:CSS3 让样式表自己就能做一部分以前只能靠 JavaScript 做的动态效果 (悬停动画、过渡),所以能用 CSS 做的动效就别动用 JavaScript33。 第 18 章会展开 flexbox、CSS Grid 这些现代布局技术。
3.5 HTML5:补媒体的窟窿¶
HTML5 补上了老 HTML 的几个硬缺口:不用插件就能在页面里放音频、视频,以及一块可以画图的画布(<canvas>)34。
它还顺手收拾了历史遗留——比如当年为了迎合从未实现的 XHTML 标准而写成的 <br />,
现在写 <br> 就行35。HTML5 今天由一个叫 WHATWG 的组织以「活标准」的方式持续维护,不再按版本号发布36。
4. 幕后两位:Apache 与 Node.js¶
上面五个角色都在「答」的那一侧干活,而真正把请求接进来、把回答发出去的,是 web 服务器软件本身。 这本书用的是 Apache——世界上装机量最大的开源 web 服务器37。
Apache 本身也是个「大管家」:
- 它不只发 HTML,图片、音频、RSS 订阅源什么都发;
- 它靠模块扩展功能——PHP 就是以模块形式挂在它身上的;
- 它还带着一批自己的模块,比如处理网址重写的 Rewrite、管安全的各种模块38。
Node.js 是 Apache 的当代挑战者。 2009 年,Ryan Dahl 不满 Apache 应付大量同时连接的方式, 用 Google 浏览器的 V8 引擎造了 Node.js——让 JavaScript 也能跑在服务器上39。 两者的模型差别很本质:Apache 给每个请求开一个线程、线程等着回应期间被占死; Node.js 是「事件驱动、非阻塞」——把耗时的活(比如读文件)交出去后立刻回头接下一个请求,等结果回来再通知它。 同样的等待,一个占着人手干等,一个先去干别的40。第 21 章专门讲它。
书里还有一个补充角色:MariaDB。Oracle 收购 MySQL 的原东家 Sun 之后, 社区担心 MySQL 不再完全开源,于是从它分叉(fork,拿一份源代码另起炉灶的意思)出了 MariaDB, 由原班人马带队,和 MySQL 高度兼容——这本书的所有例子两边都能跑41。
5. 把五个角色串起来:一个真实的协作场景¶
第一章的收尾例子是全书第一个「多角色合奏」的完整走查, 也是本组后面所有章节的缩影:注册时检查用户名是否已被占用(Gmail 就长这样)42。
① 服务器发出注册表单(HTML)
② 同一份 HTML 里附带的 JavaScript 盯着用户名输入框:
一旦有字、且用户移开了光标(点了别处或按 Tab 跳走)……
③ JavaScript 在后台把这个用户名发回服务器,等答复 —— 页面没有刷新
④ 服务器查库,答复「占用/可用」
⑤ JavaScript 在输入框旁贴上标记(绿勾或红叉)
⑥ 若名字被占而用户还是点了提交,JavaScript 拦下提交,再强调一次
图说:一次「输入即校验」,PHP、MySQL、JavaScript 各出了一段力,用户只看到一个勾。
注意这里每一步是谁在干活:表单是 PHP 发的(第 11 章),查库是 MySQL 干的(第 9 章), 后台通信是 JavaScript 的异步通信(第 17 章),连「拦下提交」也是浏览器里的 JavaScript。 服务器和浏览器两头各管一段,中间靠 HTTP 传话——这就是「动态网站」四个字的全貌。
6. 开发环境:把整套问答搬到本机(原书第 2 章)¶
上面讲的问答需要四样东西同时在场:web 服务器、PHP、MySQL,再加上浏览器。 第二章的任务就是让你自己的电脑上这四样齐备——这就是「开发服务器」的意思。
6.1 为什么要本机一套¶
最省事的替代方案是用别人的服务器(比如租一台),但那样每改一行代码都要先传到远端才能看效果; 而且写得半半拉拉的代码带着错误和安全漏洞暴露在公网上。本机一套,保存文件、刷新浏览器,立刻看到结果43。
6.2 WAMP/MAMP/LAMP:一体化安装包¶
四个组件各自安装配置都很折磨人,所以社区做了打包好的集成软件,按操作系统起名:
| 缩写 | 展开 | 平台 |
|---|---|---|
| WAMP | Windows + Apache + MySQL + PHP | Windows |
| MAMP | Mac + 同上 | macOS |
| LAMP | Linux + 同上 | Linux |
装一个就等于四样齐备,自带默认配置,开箱即用——代价是默认配置不适合当生产服务器用, 安全配置偏松,只该用来开发44。
这本书这一版推荐的是 AMPPS(一个跨平台的 WAMP/MAMP/LAMP 类产品)。 安装本身只有几步:下载安装包(写书时 Windows 版 4.4、约 46 MB)、一路 Next、 最后可能附带装一个微软运行库;装完桌面上出现一个控制窗口, 从里面一键启动/停止 Apache 和 MySQL。写书时 AMPPS 自带的默认 PHP 版本是 8.2, 想换版本在控制窗口的选项菜单里操作45。
装完先验收:浏览器打开 http://localhost——localhost 是「本机」的专用名字,
指向你自己的电脑——看到 AMPPS 的管理页,就说明服务器已经在本机跑起来了46。
6.3 document root:网站的「家门口」¶
第二个必须搞清的概念是 document root(文档根目录):服务器收到不带路径的请求时(比如 http://localhost),
就去这个目录里找文件。AMPPS 在 Windows 上默认是 C:\Program Files\Ampps\www,macOS 上是 /Applications/Ampps/www47。
验收方法: 写一个只有一行 Hello World! 的 test.html,存进 document root,
然后浏览器访问 http://localhost/test.html——看到 Hello World,整条链路就通了49。
这里有一个全书最重要的易错点,原书用 Note 框专门提醒:
从 document root 访问,和直接双击打开文件,是两回事。 前者走了完整的服务器问答(能执行 PHP、能连 MySQL);后者只是浏览器把文件读进来显示, PHP 代码会原样出现在页面上,什么都不会发生50。
如果某页出现了「源码裸露」的怪象,九成是这个原因——检查地址栏里有没有 http://localhost。
6.4 三个平台的差异一句话版¶
Windows 走 AMPPS 安装向导,文档根目录在 C:\Program Files\Ampps\www;
macOS 下载 .dmg 后把 AMPPS 文件夹拖进 Applications,文档根目录在 /Applications/Ampps/www;
Linux 发行版太多,原书不逐步讲,只教一个自查法:浏览器开 http://localhost,
能出默认页面就多半装好了 Apache,MySQL 是否在场再问系统管理员48。
差异只在这一步;装好之后,三平台上跑的例子一模一样——这也是这本书敢押注 PHP/MySQL 栈的原因之一:
上层代码完全不挑操作系统。
6.5 远程开发的规矩(如果不得不用远端服务器)¶
书里也给出了「不得不用远端服务器」时的两条安全规矩,值得记住:
- 登录用 SSH(安全外壳协议,加密的远程登录),不要用它前身 Telnet——内容明文传输,谁都能偷看; Windows 推荐 PuTTY,Mac 自带 SSH51。
- 传文件用 SFTP/FTPS,不要用老 FTP——理由一模一样,老 FTP 的用户名密码和文件内容在网上裸奔。 书里推荐的开源工具是 FileZilla52。
6.5 代码编辑器:别用记事本硬写¶
写 HTML/PHP/JavaScript 用纯文本编辑器(记事本)也能写,但专用代码编辑器有两个立刻值回票价的功能: 语法高亮(用颜色区分代码的角色,一眼看出结构)和括号配对、甚至在你运行前就标出语法错误。 书里选的是 Visual Studio Code(微软出的,免费,三大系统都能跑),理由是它正在成为行业标准53。
7. 作者的判断与证据¶
这一章是综述章,断言不多,挑三条标明成色:
| 书中的说法 | 成色 |
|---|---|
| PHP 的简单加上与 MySQL 的原生联动,用户量是 Perl 的两倍多 | 作者陈述的行业印象,给了对比但没给数据来源54 |
| Node.js 的事件驱动模型适合高并发(同时很多访客)、低延迟(响应快)场景 | 成立,且是业界共识;但「优于 Apache」是有条件的——CPU 密集的旧式网站 Apache 仍然合适(第 21 章开头原书自己也这么写)55 |
| 一切 JavaScript 校验都不能替代服务器端校验 | 全书反复强调的硬规矩,理由在第 6 节异步例子里就露了苗头:用户提交的数据你永远不能预先信任(第 16 章展开)56 |
8. 边界与局限¶
- 版本时效: 写书时 AMPPS 是 4.4 版、PHP 默认 8.2、Node.js 22.6——都是 2024 年的快照, 安装界面和版本号今天多半已经不同。装的时候照「道理」装(哪一步在干什么),不要照抄按钮位置。
- 操作系统偏向: Windows 和 macOS 有详细步骤;Linux 一句「各发行版不同」带过, Linux 用户得自己查发行版的包管理器。
- jQuery 的位置: 这一版把 jQuery 降格为「历史遗留」,主推 React 和原生 JavaScript—— 书里明确说浏览器们如今兼容性够好,不必再靠 jQuery 抹平差异57。对读者这是省事的取舍, 但意味着你接手老项目时满眼的 jQuery 代码这本书不管教。
- MariaDB 与 MySQL 的「无差别」: 说「交换使用无感」是就这本书的例子而言; 两边这些年各有新特性,新项目选型时这条要重新核实。
9. 可带走的¶
- 网页 = 问答。 浏览器问、服务器答;静态页答磁盘文件,动态页答 PHP 现场算的 HTML。
- 一次动态请求的完整链条:服务器认出
.php→ PHP 解释器执行 → SQL 交给 MySQL → 结果包进 HTML → 发回。 - 五个角色分工:PHP 算(服务器端)、MySQL 存、JavaScript 演(浏览器端)、CSS 妆扮、HTML5 补媒体。
- Apache 是接请求的管家(模块化);Node.js 用「事件驱动、非阻塞」挑战它——等的时候不闲着。
- 开发服务器 = 本机的 Apache+PHP+MySQL;一体化包叫 WAMP/MAMP/LAMP,这本书用 AMPPS。
- document root 是「家门口」;验收方法:test.html +
http://localhost/test.html。 - 从 localhost 访问 ≠ 双击打开文件——后者 PHP 不执行。
- 远端操作的安全底线:登录 SSH、传文件 SFTP,明文的老 Telnet/老 FTP 一律不用。
- 用代码编辑器(如 Visual Studio Code),不要拿记事本写代码。
- 浏览器收到的 HTML 里看不出「动态」——动态发生在服务器端,浏览器永远只收平平无奇的 HTML。
9.5 把问答旅程再走深一层(四个常被跳过的细节)¶
9.5.1 HTTP 头与体:cookie 为什么"必须在输出前"¶
第 12 章讲 cookie 时有一句硬规矩:setcookie 必须在任何 HTML 输出之前调用。 当时只说是"规矩",这里的"为什么"补上:HTTP 响应是分两截的——先是一行状态 加一组「头」(header,键值对,如 Content-Type、Set-Cookie),空一行之后才是 「体」(body,也就是 HTML 本身)。浏览器按这个顺序解析:先读完所有头,再渲染体。
PHP 的 header() 和 setcookie() 都是往「头」里写东西——一旦 echo 输出
了哪怕一个字符,PHP 就默认「头已经发完了」,后面的头命令全部失效并告警。
这就是"输出之前"的物理含义,和第 3 章省掉 ?> 防换行泄漏是同一条线:
看不见的空白也算输出。
9.5.2 缓存与代理:中间那些"帮工"¶
第 1 章的问答图里,浏览器和服务器之间"可以有几台别的设备"。最常见的两种:
- 缓存(cache):某台中间服务器把热门页面留一份副本;后来的请求若命中, 直接由它应答,源头服务器完全不知道。好处是快、省源头负载;代价是 你看到的可能不是最新内容——动态网站(如本项目的所有 .php)通常要让 响应头声明"不要缓存"(Cache-Control),静态图片则可以放心缓存。
- 代理(proxy):替一群人转发请求的服务器(公司网关、翻墙工具都是)。 Apache 自己也带 Proxy 模块,可以把某些路径转交给别的服务(第 21 章的 Node.js 常与 Apache 这样搭配:静态 PHP 走 Apache,实时通道走 Node)。
9.5.3 localhost 与 127.0.0.1:本机的两个名字¶
开发时你会见到 localhost 和 127.0.0.1 两种写法——它们是同一件事:
指向你自己的机器(回环地址,loopback)。区别在于:localhost 是名字,
127.0.0.1 是数字地址;浏览器访问 localhost 时也会先做一次"翻译"
(查 hosts 文件,通常直接映射到 127.0.0.1)。书里的例子两种写法都出现,
知道是同一个门牌即可。
9.5.4 排错清单:页面"什么都不显示"时¶
按出现频率排,逐条自查:
- 地址栏是不是
http://localhost/...? 双击打开文件的话 PHP 根本不执行 (§6.3 的易错点,九成的新手卡壳在这)。 - AMPPS 的 Apache 启动了吗? 控制面板看状态灯;80 端口被别的程序
(如 IIS、另一个 Apache)占用也会启动失败,改端口(如 8080)后访问要
带上端口号(如
localhost:8080/)。 - 文件放对目录了吗? 必须在 document root(AMPPS 的 www)里或它的 子目录里,不在桌面、不在下载文件夹。
- 保存了吗? 编辑器没保存就刷新,看的是旧文件。
- PHP 语法错误? 页面全白是 PHP 致命错误的典型症状;打开 AMPPS 的
错误日志或先把
phpinfo()放一个探针页确认 PHP 活着。
这份清单不在原书某一页,是把第 2 章安装验收、第 3 章 Parse error、 第 10 章"别输出错误给用户"三处的教训合起来的实战口袋书。
9.6 WAMP 之外的第六个角色:编辑器与版本控制(我们的延伸)¶
书里没有讲版本控制,但对"改动—刷新"这个开发循环,还有一件工具和第 2 章的 AMPPS 一样属于"开工前就该装好":版本控制(用 Git)。它解决的是 AMPPS 管不了的那类事故——"刚才改坏的版本找不回来了"。
最小用法只要三条命令,够你学完这本书:
它和安全无关、和功能无关,只和"能不能放心大胆地试"有关——综合项目那种 十几个文件来回改的场景,没有快照的胆子会小一半。(补充(不在书里,来自通用知识): Git 的版本快照存的是「差异」,几个快照只占原文件体积的一小部分。)
9.7 判定树:这一次访问,静态还是动态¶
同样是回一个页面,"谁来生成、何时生成"决定了整个链路。遇到任何一个 真实 URL,用三个问题判定它走哪条路:
URL 进来
├─ 文件后缀是 .html/.htm/.jpg/.css/.js 之类?
│ └─ 是 → 静态路:Apache 直接读文件,逐字节发回,不惊动 PHP
├─ 后缀是 .php?
│ └─ 是 → 动态路:Apache 把请求转给 PHP,PHP 产出 HTML,Apache 再发回
└─ 没有后缀、路径像 /user/42?
└─ 是 → 重写路:Apache 的 Rewrite 模块先翻译成内部真实路径,再走上面两路之一
三个追问,防止误判:
- "静态文件里也能有 JavaScript,算动态吗?" 不算。JavaScript 在 浏览器里跑,动态/静态的分界线画在服务器这一侧:响应离开服务器之前 需不需要现算。JS 再花哨,服务器发的仍是那个一成不变的 .html。
- ".php 文件里全是 HTML、一行 PHP 没有呢?" 仍是动态路—— Apache 按后缀分配处理器,不看内容。这也解释了为什么纯 HTML 页面 起名叫 .php 仍能打开,但白白多付一次 PHP 的解释成本。
- "Ajax 之后呢?" 那是本书后半(第 17 章)的异步通信: 浏览器在页面渲染完之后,再单独发一次请求只取数据。 判定树对每一次请求分别成立,一次页面访问可能串好几次。
9.8 一次 GET /index.php 的完整时序(再走深一层)¶
把 §2 的主线例子展开成带时序的走查,每一步标注"谁在场、谁不在场":
时刻 动作 谁在场
t0 浏览器解析出 http://localhost/index.php
t1 建立到 80 端口的 TCP 连接 浏览器 ↔ Apache(HTTP 守护)
t2 发出请求行 GET /index.php HTTP/1.1 同上
t3 Apache 按后缀认出这是 PHP 的活,
把请求转给 PHP 模块(同一台机内) Apache + PHP
t4 PHP 从头解释 index.php,
遇到 echo 就攒下输出缓冲 只有 PHP
t5 PHP 若查库:再向 MySQL 发一条查询 PHP ↔ MySQL
t6 PHP 收尾,把攒好的 HTML 交还 PHP → Apache
t7 Apache 加上响应头,发回浏览器 Apache
t8 浏览器收完 HTML,开始解析渲染,
遇到 <script>/<img> 再各自发请求 浏览器 ↔ Apache(静态路)
两个常被忽略的事实:
- t3 的"转交"发生在同一台机器内部,不是另一次网络请求。 PHP 模块是 Apache 的一部分(或以 CGI 方式被唤起),浏览器全程 只跟 Apache 说话——PHP 的存在对浏览器不可见1。
- t8 的后续请求各自独立走完判定树。一张网页引用的每个 CSS、 每张图都是一次全新的请求/响应,各自独立判定静态还是动态。 所谓"一次访问",其实是请求的风暴。
9.9 Apache 的模块生态:不只是 PHP 的房东¶
第 1 章明确说:Apache 不只是静态文件的搬运工,它的能力来自模块2。 把书里点名的模块排成职责表:
| 模块 | 管什么 | 本书哪里用得上 |
|---|---|---|
| PHP 模块(mod_php) | 把 .php 交给 PHP 解释 | 全书每一章 |
| Rewrite 模块 | URL 改写:把好看的地址翻译成内部路径 | 社交项目(第 22 章)的友好地址 |
| Proxy 模块 | 代理与缓存:常被请求的页面从缓存出 | 高流量站点的减负手段 |
| GD 库 | PHP 侧创建/处理图像 | PHP 动态生成图片 |
| 安全类模块 | 访问控制、加密连接 | 登录与认证(第 12 章) |
模块化的启示:Apache 是一个"按模块拼装"的服务器。 装什么模块,它就变成什么服务器;这也解释了为什么同一台 Apache 既能发静态文件、又能跑 PHP、还能做反向代理——不是它全能, 是它的积木全3。
9.10 Node.js 的出场逻辑:不是替代,是换了一种排队方式¶
第 1 章给 Node.js 的辩护词值得原样压一遍:Ryan Dahl 2009 年不满 Apache 应对大量同时连接的方式,于是用 Google 的 V8 引擎做了 Node, 让 JavaScript 也能跑在服务器侧;npm 随后解决了包的分发与共享4。
书里给的三个选择理由,浓缩成对照:
- 一种语言走全程:前端后端都是 JavaScript,少一次换脑; 但注意——Node 跑不了你的 PHP 脚本,混合系统要划清边界5。
- 事件驱动模型:Apache 传统上为每个连接配一个进程/线程, 连接一多,内存与切换成本陡增;Node 用一个主循环同时照看大量 连接,等 I/O 的空档去服务别人。原书把它列为 Node 优于 Apache 的 核心6。
- 可以混着用:一个复杂应用完全可以让 Apache+PHP 管一部分、 Node 管另一部分,各干各擅长的。
判断句(我们的判断,原书证据支持):学习期跟书走 Apache+PHP, 工程期按团队栈选 Node;两者不是宗教,是工具。
9.11 开发服务器安装决策:打包 vs 手工¶
第 2 章的 WAMP/MAMP/LAMP 是一组"打包哲学":把 Apache、MySQL、PHP 捆成一个安装包,一次装好、互相配套7。原书这一版推荐 AMPPS (Windows 上的选择;macOS、Linux 各有对应路线)8。
决策表:
| 你的处境 | 建议 | 理由 |
|---|---|---|
| 刚开始学,只想快 | 打包(AMPPS/MAMP/XAMPP) | 安装即配套,排错面小 |
| 已有现成集成环境 | 直接用 | 第 2 章明说各组件若已装好互通,例子照样跑 |
| 想理解每个部件 | 手工分装 | 慢、需要查配置,但每个报错都是一次学习 |
| 只想跑前端(后半本书) | Node + npm 即可 | 第 20/21 章的路 |
第 2 章还有一句诚实的警告:手工下载拼装各部件"可能非常耗时", 要配置到完全互通需要大量查证——这不是劝退,是把"打包的价值" 讲透:打包省的不是安装时间,是"部件之间互相认不认"的排错时间9。
9.12 localhost、控制页与文档根:三个别混淆的"入口"¶
装完开发服务器,第 2 章让你访问了几个地址,它们各是各的门:
http://localhost—— 本机的约定俗成名,等价于 127.0.0.1。 浏览器访问它,就是访问你自己机器上那个 Apache10。http://localhost/ampps/—— 安装器落下的控制页: 管 MySQL 开关、看组件版本、配参数。它是"机房的管理台", 不是你的网站11。- 文档根目录(DocumentRoot) —— Apache 认领的"网站根": 你把 .php 放进它里面,localhost 下才看得见; 放在别处,Apache 一律 404(或 403)。第 2 章让你确认它的位置, 就是建立"文件放对门牌"的条件反射12。
三个迷思各一句话:
- "localhost 是个网站" —— 不是,它是"本机"这个地址的别名, 后面挂什么服务器由你装什么决定。
- "控制页打不开 = 服务器坏了" —— 不一定。先看 Apache 是否在跑 (控制页本身也依赖它),再谈坏没坏。
- "文件在硬盘上就一定看得到" —— 只在文档根里成立。 这条迷惑过几乎所有初学者:文件明明存在,浏览器却 404, 九成是放错了目录。
9.13 Web 1.0 到动态网页:一条简史线(第 1 章背景)¶
第 1 章开头用 Web 1.0 与增强技术铺开背景:Java、JavaScript、Flash、 ActiveX 在浏览器侧各领风骚;服务器侧,CGI(Common Gateway Interface) 用 Perl 等脚本语言把"运行一个本地程序的输出"嵌进页面, 服务器端脚本由此登场13。这条线的意义在于定位 PHP:
PHP 的胜利不是技术上的"最先进",而是入门路径最短: 改一个 .php 文件、刷新浏览器、立刻看到变化。 这个"编辑-刷新"循环正是第 2 章开发环境存在的全部意义。
9.14 练习场(第 1+2 章)¶
- 判定树实操:对本机开发服务器,分别访问一个 .html、一个 .php、 一个 .css,用浏览器开发者工具的 Network 面板核对每一步的响应, 标注走的是静态路还是动态路。
- 改名实验:把一个纯 HTML 文件改成 .php 后缀,刷新看是否照常 显示;再用 Network 面板对比响应时间差异,理解"白白多付解释成本"。
- 404 实验:把一个 .php 移出文档根,访问它,读 Apache 的错误日志 找原因;移回去再验证恢复——亲手建立"文档根"的条件反射。
- 模块侦察:访问控制页,列出当前 Apache 装的所有模块, 对照 §9.9 的表,圈出 Rewrite、PHP 各是哪个。
- Node 小体验(预习第 21 章):node -e 跑一行 console.log, 感受"JavaScript 离开了浏览器也能跑"——这是第 1 章埋的伏笔。
9.15 FAQ(五问)¶
Q1:我非要用 Nginx 行不行? 第 1 章的主角是 Apache,Node.js 是对照组;Nginx 本书未展开 (书外补充:它是另一个流行的 Web 服务器,常与 PHP-FPM 搭配)。 学概念不受影响——请求/响应、静态/动态、模块拼装,换谁都成立。
Q2:开发服务器和线上服务器有什么区别? 开发服务器装在你本机、只服务你自己、出错直接看屏幕; 线上服务器服务全世界、出错要给用户看体面页面、给日志看细节。 同一个 Apache,两种性格——第 10 章的生产环境错误处理就是 "性格切换"的第一课。
Q3:PHP 为什么"每请求从头解释"?这对写法有什么影响? 两次请求之间,PHP 不替你记住任何全局状态——想跨请求记住东西, 得借 Cookie、Session 或数据库(第 11/12 章)。每请求无状态, 既是 PHP 好上手的原因(脚本内不用关心别人),也是写登录、 购物车时必须额外搭桥的原因。
Q4:AMPPS、XAMPP、MAMP 选哪个? 第 2 章这一版定的是 AMPPS;三者内核相同(Apache+MySQL+PHP), 差别在控制界面与更新节奏。选一个装上就别看别的了—— 纠结安装器是新手期最贵的拖延。
Q5:学完这两章,我该记住什么? 三条:请求/响应是万事的骨架;静态/动态的分界线画在服务器侧; 开发环境存在的意义是让"编辑-刷新"循环在三十秒内完成。 其余全是细节,用到再查。
9.16 开发环境排错速查:五种高频故障¶
装环境不是终点,是排错的起点。第 2 章的内容可以反推出一张 "症状→病因"速查表,按出现频率排:
| 症状 | 第一嫌疑 | 验证方法 |
|---|---|---|
| localhost 打不开 | Apache 没在跑 | 回控制页看 Apache 状态灯14 |
| 控制页能开、自己的页面 404 | 文件不在文档根 | 对照控制页显示的文档根路径15 |
| .php 文件被当文本显示 | PHP 模块没挂上 | 访问控制页的 phpinfo 区块 |
| MySQL 相关例子全挂 | 数据库服务没启动 | 控制页里启动 MySQL |
| 改了代码刷新没变化 | 浏览器缓存或改了错目录 | 硬刷新(加 Shift)再核路径 |
排错的两条元规则:
- 从下往上查:页面出错,先看 Apache 活没活,再看 PHP 挂没挂, 再看 MySQL 通没通,最后才看你的代码。初学者九成反过来查, 于是越查越乱。
- 一次只改一处:排错时同时动两个变量,等于没排。 AMPPS 文档和支持入口是官方给的兜底16—— 但先用速查表把"环境问题"和"代码问题"分开,再决定找不找支持。
9.17 本机与线上:部署差异清单(第 2 章的镜像问题)¶
开发服务器和线上服务器的差异,第 2 章在讲上传工具时露了一角: FTP 明文传输,不安全;SFTP、SCP 这类基于 SSH 的方式才是方向17。 把这一角展开成完整清单:
| 维度 | 本机(开发) | 线上(生产) |
|---|---|---|
| 谁在看错误 | 你自己,直接看屏幕 | 用户看体面页面,你看日志 |
| 文件怎么上去 | 无所谓,本来就都在 | SFTP/版本库部署,FTP 不要用 |
| phpinfo() | 排错利器 | 安全隐患,绝不保留 |
| 数据库连接 | root 空密码的玩具配置 | 专用账号、最小权限 |
| 出错时的 PHP | 报错全开,越响越好 | 报错关给用户、记日志给运维 |
这张表会在第 10 章(PDO 错误处理)、第 12 章(密码散列)、 第 22 章(项目收尾)反复被引用。现在就把它抄在案头: "在我的机器上是好的"不是部署完成的标准,"在线上是对的"才是。
9.18 五条主线的一次合流:这两章真正的交付物¶
第 1 章给全景,第 2 章给本机。把两章的机制合起来看, 真正交付的不是"装了什么软件",而是五条可以在任何 web 项目上 复用的主线:
- 问答主线:浏览器问、服务器答——此后每一章都只是给这个 问答加器官:PHP 让答案可算,MySQL 让答案有记性,JavaScript 让提问可以在答完之后继续。
- 分工主线:五个角色(HTML/CSS/JS/PHP/MySQL)+ 幕后两位 (Apache/Node)各管一摊,接口只有两样——HTTP 与 SQL。 换任何一项技术,接口形状不变。
- 边界主线:静态/动态的分界线画在服务器侧;信任的分界线 也画在服务器侧。两条线是同一根。
- 环境主线:开发环境的全部意义,是让"编辑-刷新"循环在 三十秒内完成;所有偏离这条的仪式(手工部署到远程再测) 都是在给学习加税。
- 排错主线:从下往上查(服务器→解释器→数据库→代码), 一次只改一处——第 2 章的安装排错,和第 22 章的项目排错, 是同一套动作。
如果你合上第 2 章时只记住了"AMPPS 装好了",那等于只看了序幕。 验收标准是:随便给一个 URL,你能用 §9.7 的判定树说出它走哪条路, 能画出 §9.8 的时序图标出每一步谁在场——能,这两章就毕业了。
9.19 本章机制与后文的接口预告¶
| 本章埋下的线 | 在后文哪里接通 |
|---|---|
| 请求/响应问答 | 第 11 章表单(浏览器替用户提问)、第 17 章异步(浏览器替页面继续问) |
| Apache + PHP 分工 | 第 10 章 PDO(PHP 反向去问 MySQL) |
| localhost / 文档根 | 第 20 章 React 开发服务器会换端口,判定树原样适用 |
| Node.js 初印象 | 第 21 章整章展开 |
| 每请求无状态 | 第 12 章 Cookie/Session 补状态 |
接口预告的意义:读后面章节时,一旦发现"这又是请求/响应", 就回本章对照——同一根骨架,每章只添一两块新骨头。
9.20 一分钟自测(第 1+2 章)¶
合上书,回答五问;答不上来的,回标的小节:
- 浏览器发出的一次请求,在哪几个时刻会惊动 PHP?(§9.8)
- 静态与动态的分界线画在哪一侧?JavaScript 很花哨的页面算哪种?(§9.7)
- localhost、控制页、文档根,分别是哪扇门?(§9.12)
- 环境排错为什么"从下往上查"?(§9.16)
- 本书为什么选 AMPPS 而不让你手工拼装?(§9.11)
全对,两章毕业;错两问以上,值得重走一遍 §9.8 的时序图—— 那是这两章的承重墙。
9.21 交接备忘:这两个最容易被下一轮翻新者误解的点¶
- 第 1 章把 Apache 与 Node.js 并列为"幕后两位",不是"新旧两位"—— 原书明确说复杂应用可以让两者各管一部分。写总结时别写成 "Node 取代 Apache",那是过度概括,原书不支持。
- 第 2 章推荐的 AMPPS 是"这一版的选择",不是永恒答案; 不同版本换过推荐对象。引用时带版本语境,别把推荐写成教义。
10. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| Web 的起源(CERN、Tim Berners-Lee) | Chapter 1. Introduction to Dynamic Web Content | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:7(搜「State-of-the-art experiments at CERN」) |
| Web 1.0 与 2.0 之别 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:20(搜「content consumers」) |
| HTTP 与 HTML 的定义 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:52(搜「communication standard」) |
| 静态请求七步 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:71(搜「asking the web server」)· :131(搜「once for each object」) |
| DNS 查 IP | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:135(搜「Domain Name System」) |
| 动态请求完整链条 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:139(搜「picture of a raincoat」)· :186(搜「PHP interpreter」) |
| MariaDB 分叉始末 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:273(搜「forked from it」) |
| PHP 嵌入 HTML 的写法 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:294(搜「Today is」) |
| MySQL 与平面文件之争 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:341(搜「flat」) |
| 数据库≈Excel 文件的比方 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:349(搜「Excel spreadsheet」) |
| JavaScript 与 Java 的命名误会 | 同上 | text/24-ch13-chapter-13-exploring-javascript.txt:11(搜「marketing ploy」) |
| CSS3 接替部分 JavaScript 动效 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:453(搜「level of dynamic interactivity」) |
| HTML5 的 audio/video/canvas | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:502(搜「canvas」) |
| Node.js 的三条理由 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:551(搜「Ryan Dahl」)· :559(搜「nonblocking」) |
| 用户名检查的多角色协作 | 同上 | text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:618(搜「necessary details」)· :661(搜「nowhere near as tidy」) |
| 本地开发的两大好处 | Chapter 2. Setting Up a Development Server | text/05-ch02-chapter-2-setting-up-a-development-server.txt:15(搜「embarrassing errors」) |
| WAMP/MAMP/LAMP 的含义与安全提醒 | 同上 | text/05-ch02-chapter-2-setting-up-a-development-server.txt:48(搜「never install such a setup」) |
| AMPPS 安装与 PHP 8.2 默认值 | 同上 | text/05-ch02-chapter-2-setting-up-a-development-server.txt:72(搜「best option」)· :163(搜「8.2」) |
| document root 定义与位置 | 同上 | text/05-ch02-chapter-2-setting-up-a-development-server.txt:220(搜「contains the main web documents」) |
| localhost 访问 ≠ 打开文件 | 同上 | text/05-ch02-chapter-2-setting-up-a-development-server.txt:264(搜「different from loading」) |
| SSH 与 PuTTY | 同上 | text/05-ch02-chapter-2-setting-up-a-development-server.txt:443(搜「much more secure」) |
| 禁用 FTP、推荐 SFTP | 同上 | text/05-ch02-chapter-2-setting-up-a-development-server.txt:474(搜「insecure」) |
| Visual Studio Code 的选择理由 | 同上 | text/05-ch02-chapter-2-setting-up-a-development-server.txt:508(搜「Visual Studio Code」) |
-
出处:「Chapter 1. Introduction to Dynamic Web Content」第 71 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:71,搜「request/response process」)。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 520 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:520,搜「Apache Web Server」)。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 536 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:536,搜「Rewrite module」)。Rewrite、Proxy、安全模块并列见同段。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 551 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:551,搜「Ryan Dahl」);npm 见同段。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 563 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:563,搜「full-stack development environment」)。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 730 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:730,搜「event-driven」)。章末复习题把"事件驱动为何更优"列为考点。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 40 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:40,搜「abbreviations」)与第 44 段(:44,搜「bind the bundled programs」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 72 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:72,搜「AMPPS looks like the best option」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 59 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:59,搜「very time-consuming」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 177 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:177,搜「localhost」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 191 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:191,搜「main control page」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 195 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:195,搜「document root」)。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 238 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:238,搜「Common Gateway Interface」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 191 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:191,搜「main control page」)。控制页是组件状态的统一入口。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 195 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:195,搜「document root」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 152 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:152,搜「AMPPS documentation」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 474 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:474,搜「FTP is insecure」)。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 88 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:88,搜「You enter」)。原书列了七步,从输入网址到浏览器显示。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 135 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:135,搜「Domain Name System」)。原话:浏览器「consults an additional internet service called the Domain Name System」把名字换成地址。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 52 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:52,搜「communication standard」)。HTTP 被定义为「governing the requests and responses」的标准;服务器「accept a request from the client」。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 60 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:60,搜「listening for an incoming connection」)。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 131 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:131,搜「once for each object」)。页面里每个对象——图、视频、样式表——都要各走一遍这个流程。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 139 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:139,搜「picture of a raincoat」)与第 150 段(text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:150,搜「dynamic sequence」)。雨衣例子之后紧跟动态序列的九步清单。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 186 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:186,搜「passes the page to the PHP interpreter」)。第 192 段(:192,搜「executes the PHP code」)是执行;第 198 段(:198,搜「SQL statements」)是 SQL 转交 MySQL;第 204 段(:204,搜「returns the results」)是结果返回。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 299 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:299,搜「all of the following code」)。<?php到?>之间的代码由 PHP 处理,之外的一切作为纯 HTML 直接发给客户端。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 33–37 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:52,搜「the term server is used」)。原文:「The natural counterpart to a server is a client, so that term is applied both to the web browser and the computer on which it’s running.」 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 341 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:341,搜「flat」)。原文指出平面文件的问题:同时访问容易写坏、变大后难管理难搜索。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 349 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:349,搜「Excel spreadsheet」)。「the spreadsheet file can be viewed as a database and the individual sheets as tables」。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 358 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:358,搜「INSERT INTO users VALUES」)与第 369 段(:369,搜「SELECT surname,firstname」)。两条命令在原书里都是独立成段的原样引用。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 394 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:394,搜「checking email address validity」)。「JavaScript was created to enable scripting access to all the elements of an HTML document」。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 11 段(
text/24-ch13-chapter-13-exploring-javascript.txt:11,搜「marketing ploy」)。命名「was just a marketing ploy」,借 Java 的名气。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 442 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:442,搜「resemble standalone programs」)。「web pages perform data handling and send requests to web servers in the background」。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 453 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:453,搜「previously supported only by JavaScript」)。第 18 章开头作者明确建议用 CSS 而不是 JavaScript 实现动态特性。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 502 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:502,搜「audio」)。<audio>、<video>、<canvas>三元素。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 511 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:511,搜「full circle」)。XHTML 未实现,<br>写法回转;React 的 JSX 例外,需要/>。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 498 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:498,搜「HTML Living Standard」)。HTML5 现由 WHATWG 维护。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 524 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:524,搜「sixth hero」)。「there’s a sixth hero in the dynamic web: the web server. For this book, that means the Apache web server」。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 536 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:536,搜「Rewrite module」)。模块举例:安全模块、Rewrite(网址重写)、Proxy(缓存转发)。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 551 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:551,搜「Ryan Dahl」)。「dissatisfied with Apache and its difficulties with handling large numbers of concurrent connections」。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 559 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:559,搜「nonblocking I/O model」)与「Chapter 21. Introduction to Node.js」第 15 段(text/32-ch21-chapter-21-introduction-to-node-js.txt:15,搜「blocked until the response is ready」)。线程模型的「占着等」与事件模型的「先去干别的」是第 21 章开头的核心对比。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 273 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:273,搜「forked from it」)。「you may well encounter MariaDB on some servers in place of MySQL」。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 601 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:601,搜「checking whether a desired username」)。第 636 段(:636,搜「has been taken」)是服务器查库答复;第 661 段(:661,搜「nowhere near as tidy」)对比了无异步时整表提交重载的笨办法。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 15 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:15,搜「embarrassing errors」)。本机测试「can be as easy as saving an update」,且不必担心「embarrassing errors or security problems」暴露公网。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 48 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:48,搜「never install such a setup」)。「The security configurations of such an installation will not be as tight... you should never install such a setup as a production server.」 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 72 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:72,搜「best option」)与第 163 段(:163,搜「8.2」)。安装包版本与默认 PHP 版本都是写书时的快照。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 172 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:172,搜「verify that everything is working」)。用 localhost 地址调出管理页验收。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 220 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:220,搜「contains the main web documents」)与第 229 段(:229,搜「Ampps」)、第 364 段(:364,搜「Applications」)。两个平台的默认 document root。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 408 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:408,搜「dozens of popular flavors」)与第 412 段(:419,搜「probably have the Apache server installed」)。Linux 发行版众多、装法各异,原书只给自查思路。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 231 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:231,搜「Hello World」)与第 250 段(:255,搜「test.html」)。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 264 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:264,搜「different from loading」)。「The former will ensure access to PHP, MySQL... the latter will simply load the file into the browser」。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 443 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:443,搜「much more secure」)。「SSH is much more secure than the Telnet protocol」。 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 474 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:474,搜「insecure」)。「FTP is insecure and should not be used.」 ↩ -
出处:「Chapter 2. Setting Up a Development Server」第 504 段(
text/05-ch02-chapter-2-setting-up-a-development-server.txt:504,搜「colored syntax highlighting」)与第 508 段(:508,搜「Visual Studio Code」)。「show your syntax errors before you even run a program」。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 242 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:242,搜「more than double the number of users」)。这是作者对 PHP 与 Perl 装机量对比的陈述,未附数据来源。 ↩ -
出处:「Chapter 21. Introduction to Node.js」第 32 段(
text/32-ch21-chapter-21-introduction-to-node-js.txt:32,搜「Apache remains a strong choice」)。原文承认 Apache 在 CPU 密集场景仍是强选择,两者可搭配用。 ↩ -
出处:「Chapter 1. Introduction to Dynamic Web Content」第 394 段(
text/04-ch01-chapter-1-introduction-to-dynamic-web-content.txt:394,搜「cannot be relied upon for security」)。「it cannot be relied upon for security, which should always be performed on the web server」。 ↩ -
出处:「Chapter 20. Introduction to React」第 11 段(
text/31-ch20-chapter-20-introduction-to-react.txt:11,搜「need to rely on frameworks」)。「these days JavaScript has grown sufficiently in scope and flexibility that programmers need to rely on frameworks like jQuery a lot less」。 ↩