蚊章汇 - Web
type: channel
link: https://linuxcn.bwsl.wang/tag/Web/
items: 硬核观察 #990 Windows 11 将默认采用 ReFS 文件系统
items: 如何调用没有文档说明的 Web API
items: Web 的成长，就是一篇浏览器的故事
items: 对网站进行归档
items: 极客漫画：Web 服务器中的生活
items: 如何用树莓派搭建个人 web 服务器
items: 搭个 Web 服务器（三）
items: 漫游 HTTP/2
items: 如何在 CentOS 7 用 cPanel 配置 Nginx 反向代理
items: 搭个 Web 服务器（二）

硬核观察 #990 Windows 11 将默认采用 ReFS 文件系统
type: item
date: 2023-05-04T04:07:13+08:00
description: Windows 11 将默认采用 ReFS 文件系统微软正准备改进 Windows 11 的安全功能，他们用 Rust 重新编码内核，并使用弹性文件系统（ReFS）而不是 NTFS 作为默认文件系统。让 Windows 在内核中使用 Rust 启动这件事我们之前已经 报道 过了。ReFS 发布于 2012 年，但之前只支持 Windows Server 等企业级操作系统。它在很多方面都优于 1993 年发布的 NTFS，包括自动完整性检查和数据清理、避免需要运行 chkdsk、内置硬盘驱动器故障和冗余的处理、集成 RAID 功能等等。它将在未来几个月提供给 Windows 11 用户。消息来源：Windows Latest老王点评：感觉 Windows 真正开始变的更好了。欧洲核子研究中心庆祝将 Web 释放到公共领域 30 周年1990 年，欧洲核子研究中心的研究员蒂姆·伯纳斯-李开始着手“使用 NeXTStep 开发环境开发一个超文本 GUI 浏览器+编辑器。他创造了 ‘WorldWideWeb’ 作为该程序的名称”。到 1993 年 1 月，世界上有大约 50 个 HTTP 服务器。接下来的一个月，第一个图形浏览器 Mosaic 出现了。1993 年 4 月 30 日，欧洲核子研究中心签署了一项决定，即万维网 —— 在其屋顶下创建的客户端、服务器和代码库 —— 属于全人类（该信于 5 月 3 日正式盖章）。消息来源：The Register老王点评：正是这些科学家的无私，才有了今天的网络世界。其意义影响深远。纽约警局敦促市民购买 AirTag 以应对汽车盗窃案之前，我们报道过，由于 CAN 总线的安全缺陷，通过简单的设备很容易就可以盗窃汽车，尤其是现代和奇亚汽车。纽约市警察局召开新闻发布会称，今年到目前为止，纽约市有 966 辆现代汽车和奇亚汽车被盗，已经超过了 2022 全年总数。他们号召市民为他们的车辆配备苹果 AirTag，“参与”打击汽车盗窃。配备 AirTag 的被盗车辆的用户将看到警方使用“无人机、StarChase 技术和良好的老式警察工作来安全地找回你的被盗汽车。”他们在 Twitter 上说，“助人自助，买个标签”。消息来源：Ars Technica老王点评：苹果推出 AirTag 时恐怕没想过它居然成了随车设备。

如何调用没有文档说明的 Web API
type: item
date: 2022-03-15T18:31:25+08:00
description: 大家好！几天前我写了篇 小型的个人程序 的文章，里面提到了调用没有文档说明的“秘密” API 很有意思，你需要从你的浏览器中把 cookies 复制出来才能访问。有些读者问如何实现，因此我打算详细描述下，其实过程很简单。我们还会谈谈在调用没有文档说明的 API 时，可能会遇到的错误和道德问题。我们用谷歌 Hangouts 举例。我之所以选择它，并不是因为这个例子最有用（我认为官方的 API 更实用），而是因为在这个场景中更有用的网站很多是小网站，而小网站的 API 一旦被滥用，受到的伤害会更大。因此我们使用谷歌 Hangouts，因为我 100% 肯定谷歌论坛可以抵御这种试探行为。我们现在开始！第一步：打开开发者工具，找一个 JSON 响应我浏览了 https://hangouts.google.com，在Firefox的开发者工具中打开“ruby网络rtNetwork/rt/ruby”标签，找到一个 JSON 响应。你也可以使用 Chrome 的开发者工具。打开之后界面如下图：找到其中一条 “ 类型 Type ” 列显示为 json 的请求。为了找一条感兴趣的请求，我找了好一会儿，突然我找到一条 “people” 的端点，看起来是返回我们的联系人信息。听起来很有意思，我们来看一下。第二步：复制为 cURL下一步，我在感兴趣的请求上右键，点击 “复制Copy” -> “ 复制为 cURL Copy as cURL ”。然后我把 curl 命令粘贴到终端并运行。下面是运行结果：$ curl 'https://people-pa.clients6.google.com/v2/people/?key=REDACTED' -X POST ........ （省略了大量请求标头） Warning: Binary output can mess up your terminal. Use "--output -" to tell Warning: curl to output it to your terminal anyway, or consider "--output Warning: <FILE>" to save to a file. 你可能会想 —— 很奇怪，“二进制的输出在你的终端上无法正常显示” 是什么错误？原因是，浏览器默认情况下发给服务器的请求头中有 Accept-Encoding: gzip, deflate 参数，会把输出结果进行压缩。我们可以通过管道把输出传递给 gunzip 来解压，但是我们发现不带这个参数进行请求会更简单。因此我们去掉一些不相关的请求头。第三步：去掉不相关的请求头下面是我从浏览器获得的完整 curl 命令。有很多行！我用反斜杠（\）把请求分开，这样每个请求头占一行，看起来更清晰：curl 'https://people-pa.clients6.google.com/v2/people/?key=REDACTED' \ -X POST \ -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0' \ -H 'Accept: */*' \ -H 'Accept-Language: en' \ -H 'Accept-Encoding: gzip, deflate' \ -H 'X-HTTP-Method-Override: GET' \ -H 'Authorization: SAPISIDHASH REDACTED' \ -H 'Cookie: REDACTED' -H 'Content-Type: application/x-www-form-urlencoded' \ -H 'X-Goog-AuthUser: 0' \ -H 'Origin: https://hangouts.google.com' \ -H 'Connection: keep-alive' \ -H 'Referer: https://hangouts.google.com/' \ -H 'Sec-Fetch-Dest: empty' \ -H 'Sec-Fetch-Mode: cors' \ -H 'Sec-Fetch-Site: same-site' \ -H 'Sec-GPC: 1' \ -H 'DNT: 1' \ -H 'Pragma: no-cache' \ -H 'Cache-Control: no-cache' \ -H 'TE: trailers' \ --data-raw 'personId=101777723309&personId=1175339043204&personId=11152665…

Web 的成长，就是一篇浏览器的故事
type: item
date: 2021-02-19T00:18:08+08:00
description: 互联网诞生之时我的个人故事。最近，我和大家 分享了 我在 1994 年获得英国文学和神学学位离开大学后，如何在一个人们还不知道 Web 服务器是什么的世界里成功找到一份运维 Web 服务器的工作。我说的“世界”，并不仅仅指的是我工作的机构，而是泛指所有地方。Web 那时当真是全新的 —— 人们还正尝试理出头绪。那并不是说我工作的地方（一家学术出版社）特别“懂” Web。这是个大部分人还在用 28.8K 猫（调制解调器，俗称“猫”）访问网页的世界。我还记得我拿到 33.6K 猫时有多激动。至少上下行速率不对称的日子已经过去了， [1] 以前 1200/300 的带宽描述特别常见。这意味着（在同一家机构的）印刷人员制作的设计复杂、色彩缤纷、纤毫毕现的文档是完全不可能放在 Web 上的。我不能允许在网站的首页出现大于 40k 的 GIF 图片，这对我们的许多访问者来说是很难接受的。大于大约 60k 图片的会作为独立的图片，以缩略图链接过去。如果说市场部只有这一点不喜欢，那是绝对是轻描淡写了。更糟的是布局问题。“浏览器决定如何布局文档，”我一遍又一遍地解释，“你可以使用标题或者段落，但是文档在页面上如何呈现并不取决于文档，而是取决于渲染器！”他们想控制这些，想要不同颜色的背景。后来明白了那些不能实现。我觉得我就像是参加了第一次讨论层叠样式表（CSS）的 W3C 会议，并进行了激烈地争论。关于文档编写者应控制布局的建议真令人厌恶。 [2] CSS 花了一些时间才被人们采用，与此同时，关心这些问题的人搭上了 PDF 这种到处都是安全问题的列车。如何呈现文档不是唯一的问题。作为一个实体书出版社，对于市场部来说，拥有一个网站的全部意义在于，让客户（或者说潜在的客户）不仅知道一本书的内容，而且知道买这本书需要花多少钱。但这有一个问题，你看，互联网，包括快速发展的万维网，是开放的，是所有都免费的自由之地，没有人会在意钱；事实上，在那里谈钱是要回避和避免的。我和主流“网民”的看法一致，认为没必要把价格信息放在线上。我老板，以及机构里相当多的人都持相反的意见。他们觉得消费者应该能够看到书要花多少钱。他们也觉得我的银行经理也会想看到我的账户里每个月进了多少钱，如果我不认同他们的观点的话，那我的收入就可能堪忧。幸运的是，在我被炒鱿鱼之前，我已经自己认清了一些 —— 可能是在我开始迈入 Web 的几星期之后，Web 已经发生变化，有其他人公布他们的产品价格信息。这些新来者通常被那些从早期就开始运行 Web 服务器的老派人士所看不起， [3] 但很明显，风向是往那边吹的。然而，这并不意味着我们的网站就赢得了战争。作为一个学术出版社，我们和大学共享一个域名（在 “ac.uk” 下）。大学不太相信发布价格信息是合适的，直到出版社的一些资深人士指出，普林斯顿大学出版社正在这样做，如果我们不做……看起来是不是有点傻？有趣的事情还没完。在我担任站点管理员（“webmaster@…”）的短短几个月后，我们和其他很多网站一样开始看到了一种令人担忧的趋势。某些访问者可以轻而易举地让我们的 Web 服务器跪了。这些访问者使用了新的网页浏览器：网景浏览器（Netscape）。网景浏览器实在太恶劣了，它居然是多线程的。这为什么是个问题呢？在网景浏览器之前，所有的浏览器都是单线程。它们一次只进行一个连接，所以即使一个页面有五张 GIF 图， [4] 也会先请求 HTML 基本文件进行解析，然后下载第一张 GIF，完成，接着第二张，完成，如此类推。事实上，GIF 的顺序经常出错，使得页面加载得非常奇怪，但这也是常规思路。而粗暴的网景公司的人决定，它们可以同时打开多个连接到 Web 服务器，比如说，可以同时请求所有的 GIF！为什么这是个问题呢？好吧，问题就在于大多数 Web 服务器都是单线程的。它们不是设计来一次进行多个连接的。确实，我们运行的 HTTP 服务的软件（MacHTTP）是单线程的。尽管我们花钱购买了它（最初是共享软件），但我们用的这版无法同时处理多个请求。互联网上爆发了大量讨论。这些网景公司的人以为他们是谁，能改变世界的运作方式？它应该如何工作？大家分成了不同阵营，就像所有的技术争论一样，双方都用各种技术热词互丢。问题是，网景浏览器不仅是多线程的，它也比其他的浏览器更好。非常多 Web 服务器代码维护者，包括 MacHTTP 作者 Chuck Shotton 在内，开始坐下来认真地在原有代码基础上更新了多线程测试版。几乎所有人立马转向测试版，它们变得稳定了，最终，浏览器要么采用了这种技术，变成多线程，要么就像所有过时产品一样销声匿迹了。 [5] 对我来说，这才是 Web 真正成长起来的时候。既不是网页展示的价格，也不是设计者能定义你能在网页上看到什么， [6] 而是浏览…

对网站进行归档
type: item
date: 2018-12-03T18:07:00+08:00
description: 我最近深入研究了网站归档，因为有些朋友担心遇到糟糕的系统管理或恶意删除时失去对放在网上的内容的控制权。这使得网站归档成为系统管理员工具箱中的重要工具。事实证明，有些网站比其他网站更难归档。本文介绍了对传统网站进行归档的过程，并阐述在面对最新流行单页面应用程序（SPA）的现代网站时，它有哪些不足。转换为简单网站手动编码 HTML 网站的日子早已不复存在。现在的网站是动态的，并使用最新的 JavaScript、PHP 或 Python 框架即时构建。结果，这些网站更加脆弱：数据库崩溃、升级出错或者未修复的漏洞都可能使数据丢失。在我以前是一名 Web 开发人员时，我不得不接受客户这样的想法：希望网站基本上可以永久工作。这种期望与 web 开发“快速行动和破除陈规”的理念不相符。在这方面，使用 Drupal 内容管理系统（CMS）尤其具有挑战性，因为重大更新会破坏与第三方模块的兼容性，这意味着客户很少承担的起高昂的升级成本。解决方案是将这些网站归档：以实时动态的网站为基础，将其转换为任何 web 服务器可以永久服务的纯 HTML 文件。此过程对你自己的动态网站非常有用，也适用于你想保护但无法控制的第三方网站。对于简单的静态网站，古老的 Wget 程序就可以胜任。然而镜像保存一个完整网站的命令却是错综复杂的：$ nice wget --mirror --execute robots=off --no-verbose --convert-links \ --backup-converted --page-requisites --adjust-extension \ --base=./ --directory-prefix=./ --span-hosts \ --domains=www.example.com,example.com http://www.example.com/以上命令下载了网页的内容，也抓取了指定域名中的所有内容。在对你喜欢的网站执行此操作之前，请考虑此类抓取可能对网站产生的影响。上面的命令故意忽略了 robots.txt 规则，就像现在归档者的习惯做法，并以尽可能快的速度归档网站。大多数抓取工具都可以选择在两次抓取间暂停并限制带宽使用，以避免使网站瘫痪。上面的命令还将获取 “页面所需（LCTT 译注：单页面所需的所有元素）”，如样式表（CSS）、图像和脚本等。下载的页面内容将会被修改，以便链接也指向本地副本。任何 web 服务器均可托管生成的文件集，从而生成原始网站的静态副本。以上所述是事情一切顺利的时候。任何使用过计算机的人都知道事情的进展很少如计划那样；各种各样的事情可以使程序以有趣的方式脱离正轨。比如，在网站上有一段时间很流行日历块。内容管理系统会动态生成这些内容，这会使爬虫程序陷入死循环以尝试检索所有页面。灵巧的归档者可以使用正则表达式（例如 Wget 有一个 --reject-regex 选项）来忽略有问题的资源。如果可以访问网站的管理界面，另一个方法是禁用日历、登录表单、评论表单和其他动态区域。一旦网站变成静态的，（那些动态区域）也肯定会停止工作，因此从原始网站中移除这些杂乱的东西也不是全无意义。JavaScript 噩梦很不幸，有些网站不仅仅是纯 HTML 文件构建的。比如，在单页面网站中，web 浏览器通过执行一个小的 JavaScript 程序来构建内容。像 Wget 这样的简单用户代理将难以重建这些网站的有意义的静态副本，因为它根本不支持 JavaScript。理论上，网站应该使用渐进增强技术，在不使用 JavaScript 的情况下提供内容和实现功能，但这些指引很少被人遵循 —— 使用过 NoScript 或 uMatrix 等插件的人都知道。传统的归档方法有时会以最愚蠢的方式失败。在尝试为一个本地报纸网站（pamplemousse.ca）创建备份时，我发现 WordPress 在包含 的 JavaScript 末尾添加了查询字符串（例如：?ver=1.12.4）。这会使提供归档服务的 web 服务器不能正确进行内容类型检测，因为其靠文件扩展名来发送正确的 Content-Type 头部信息。在 web 浏览器加载此类归档时，这些脚本会加载失败，导致动态网站受损。随着 web 向使用浏览器作为执行任意代码的虚拟机转化，依赖于纯 HTML 文件解析的归档方法也需要随之适应。这个问题的解决方案是在抓取时记录（以及重现）服务器提供的 HTTP 头部信息，实际上专业的归档者就使用这种方法。创建和显示 WARC 文件在 互联网档案馆 Internet Archive 网站，Brewster Kahle 和 Mike Burner 在 1996 年设计了 ARC （即 “ARChive”）文件格式，以提供一…

极客漫画：Web 服务器中的生活
type: item
date: 2017-06-30T17:56:00+08:00
description: Web 服务器总是忙忙碌碌的，从不下班，这似乎比运维工程师还要辛苦。每一个线程都在忙着，然而也有不太一样的，比如那个被数据库操作拖在那里的，就只能发呆；而那个被糟糕的代码搞得堆栈溢出的，看起来已经要崩溃了。处理完请求之后，Web 服务器会给出生成的页面和 Cookie（饼干），如果下次带着这些饼干的编号来，那就可以很快地找到你要的饼干——这就是用饼干保存的会话。这就是 Tomcat Web 服务器里面的生活。via: http://turnoff.us/geek/life-in-a-web-server/作者：Daniel Stori 译者：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出

如何用树莓派搭建个人 web 服务器
type: item
date: 2017-05-15T04:40:00+08:00
description: 个人 Web 服务器即 “云”，只不过是你拥有和控制它，而不是一个大型公司。拥有一个自己的云有很多好处，包括可定制、免费存储、免费的互联网服务、通往开源软件之路、高安全性、完全控制您的内容、快速更改的能力、实验代码的地方等等。 这些好处大部分是无法估量的，但在财务上，这些好处可以为您每个月节省超过 100 美元。我本可以选择 AWS ，但我更喜欢完全自由且安全性可控，并且我可以学一下这些东西是如何搭建的。私有 Web 托管：而非 BlueHost 或 DreamHost云存储：而非 Dropbox、Box、Google Drive、Microsoft Azure、iCloud 或是 AWS自主部署安全HTTPS：Let’s Encrypt分析： GoogleOpenVPN：不需要专有互联网连接（预计每个月花费 $7）我所使用的物品清单：树莓派 3 代 Model BMicroSD 卡（推荐使用 32 GB， 兼容树莓派的 SD 卡）USB microSD 卡读卡器以太网络线连接上 Wi-Fi 的路由器树莓派盒子亚马逊倍思的 MicroUSB 数据线苹果的充电器USB 鼠标USB 键盘HDMI 线材显示器 (支持接入 HDMI)MacBook Pro步骤 1： 启动树莓派下载最新发布的 Raspbian (树莓派的操作系统)。 Raspbian Jessie 的 ZIP 包就可以用 [脚注 1]。解压缩或提取下载的文件然后把它拷贝到 SD 卡里。使用 Pi Filler 可以让这些过程变得更简单。下载 Pi Filer 1.3 或最新的版本。解压或提取下载文件之后打开它，你应该会看到这样的提示：确保 USB 读卡器这时还没有插上。如果已经插上了那就先弹出。点 “Continue” 继续下一步。你会看到一个让你选择文件的界面，选择你之前解压缩后的树莓派系统文件。然后你会看到另一个提示，如图所示：把 MicroSD 卡（推荐 32 GB ，至少 16GB）插入到 USB MicroSD 卡读卡器里。然后把 USB 读卡器接入到你的电脑里。你可以把你的 SD 卡重命名为 “Raspberry” 以区别其他设备。然后点击 “Continue”。请先确保你的 SD 卡是空的，因为 Pi Filler 会在运行时 擦除 所有事先存在 SD 卡里的内容。如果你要备份卡里的内容，那你最好就马上备份。当你点 “Continue” 的时候，Raspbian OS 就会被写入到 SD 卡里。这个过程大概会花费一到三分钟左右。当写入完成后，推出 USB 读卡器，把 SD 卡拔出来插入到树莓派的 SD 卡槽里。把电源线接上，给树莓派供电。这时树莓派就会自己启动。树莓派的默认登录账户信息是：用户名： pi密码：raspberry当树莓派首次启动完成时，会跳出一个标题为 “ 设置选项 Setup Options ” 的配置界面，就像下面的图片一样 [脚注 2]：选择 “ 扩展文件系统 Expand Filesystem ” 这一选项并回车 [脚注 3]。 同时，我还推荐选择第二个选项 “ 修改密码 Change User Password ”。这对保证安全性来说尤为重要。它还能个性化你的树莓派。在选项列表中选择第三项 “ 启用引导到桌面 Enable Boot To Desktop/Scratch ” 并回车。这时会跳到另一个标题为 “ 选择引导选项 Choose boot option ” 的界面，就像下面这张图这样：在这个界面选择第二个选项 “ 以用户‘pi’登录图形化桌面 Desktop log in as user 'pi' at the graphical desktop ” 并回车 [脚注 4]。完成这个操作之后会回到之前的 “ 设置选项 Setup Options ” 界面。如果没有回到之前的界面的话就选择当前界面底部的 “OK” 按钮并回车。当这些操作都完成之后，选择当前界面底部的 “Finish” 按钮并回车，这时它就会自动重启。如果没有自动重启的话，就在终端里使用如下命令来重启。$ sudo reboot 接上一步的重启，如果所有步骤都顺利进行的话，你会进入到类似下面这样桌面环境中。当你进入了桌面之后，在终端中执行如下命令来更新树莓派的固件。$ sudo apt-get update $ sudo apt-get upgrade-y $ sudo apt-get dist-upgrade -y $ sudo rpi-update 这些操作可能会花费几分钟时间。完成之后，现在运行着的树莓派就是最新的了。步骤 2： 配置树莓派SSH 指的是 Secure Shell，是一种加密网络协议，可让你在计算机和树莓派之间安全地传输数据。 你可以从 M…

搭个 Web 服务器（三）
type: item
date: 2016-10-09T22:42:00+08:00
description: “只有在创造中才能够学到更多。” ——皮亚杰在本系列的第二部分中，你创造了一个可以处理基本 HTTP GET 请求的、朴素的 WSGI 服务器。当时我问了一个问题：“你该如何让你的服务器在同一时间处理多个请求呢？”在这篇文章中，你会找到答案。系好安全带，我们要认真起来，全速前进了！你将会体验到一段非常快速的旅程。准备好你的 Linux、Mac OS X（或者其他 *nix 系统），还有你的 Python。本文中所有源代码均可在 GitHub 上找到。服务器的基本结构及如何处理请求首先，我们来回顾一下 Web 服务器的基本结构，以及服务器处理来自客户端的请求时，所需的必要步骤。你在第一部分及第二部分中创建的轮询服务器只能够一次处理一个请求。在处理完当前请求之前，它不能够接受新的客户端连接。所有请求为了等待服务都需要排队，在服务繁忙时，这个队伍可能会排的很长，一些客户端可能会感到不开心。这是轮询服务器 webserver3a.py 的代码：##################################################################### # 轮询服务器 - webserver3a.py # # # # 使用 Python 2.7.9 或 3.4 # # 在 Ubuntu 14.04 及 Mac OS X 环境下测试通过 # ##################################################################### import socket SERVER_ADDRESS = (HOST, PORT) = '', 8888 REQUEST_QUEUE_SIZE = 5 def handle_request(client_connection): request = client_connection.recv(1024) print(request.decode()) http_response = b"""\ HTTP/1.1 200 OK Hello, World! """ client_connection.sendall(http_response) def serve_forever(): listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) listen_socket.bind(SERVER_ADDRESS) listen_socket.listen(REQUEST_QUEUE_SIZE) print('Serving HTTP on port {port} ...'.format(port=PORT)) while True: client_connection, client_address = listen_socket.accept() handle_request(client_connection) client_connection.close() if __name__ == '__main__': serve_forever() 为了观察到你的服务器在同一时间只能处理一个请求的行为，我们对服务器的代码做一点点修改：在将响应发送至客户端之后，将程序阻塞 60 秒。这个修改只需要一行代码，来告诉服务器进程暂停 60 秒钟。这是我们更改后的代码，包含暂停语句的服务器 webserver3b.py：###################################################################### # 轮询服务器 - webserver3b.py # # # # 使用 Python 2.7.9 或 3.4 # # 在 Ubuntu 14.04 及 Mac OS X 环境下测试通过 # # # # - 服务器向客户端发送响应之后，会阻塞 60 秒 # ###################################################################### import socket import time SERVER_ADDRESS = (HOST, PORT) = '', 8888 REQUEST_QUEUE_SIZE = 5 def handle_request(client_connection): request = client_connection.recv(1024) print(request.decode()) http_…

漫游 HTTP/2
type: item
date: 2016-09-27T06:20:00+08:00
description: 自从我写了上一篇博文之后，就再也找不到空闲时间写文章了。今天我终于可以抽出时间写一些关于 HTTP 的东西。我认为每一个 web 开发者都应该对这个支撑了整个 Web 世界的 HTTP 协议有所了解，这样才能帮助你更好的完成开发任务。在这篇文章中，我将讨论什么是 HTTP，它是怎么产生的，它的地位，以及我们应该怎么使用它。HTTP 是什么首先我们要明白 HTTP 是什么。HTTP 是一个基于 TCP/IP 的应用层通信协议，它是客户端和服务端在互联网互相通讯的标准。它定义了内容是如何通过互联网进行请求和传输的。HTTP 是在应用层中抽象出的一个标准，使得主机（客户端和服务端）之间的通信得以通过 TCP/IP 来进行请求和响应。TCP 默认使用的端口是 80，当然也可以使用其它端口，比如 HTTPS 使用的就是 443 端口。HTTP/0.9 - 单行协议 (1991)HTTP 最早的规范可以追溯到 1991 年，那时候的版本是 HTTP/0.9，该版本极其简单，只有一个叫做 GET的请求方式。如果客户端要访问服务端上的一个页面，只需要如下非常简单的请求：GET /index.html 服务端对应的返回类似如下：(response body) (connection closed) 就这么简单，服务端捕获到请求后立马返回 HTML 并且关闭连接，在这之中没有 头信息 （ headers ） 仅支持 GET 这一种请求方法必须返回 HTML如同你所看到的，当时的 HTTP 协议只是一块基础的垫脚石。HTTP/1.0 - 1996在 1996 年，新版本的 HTTP 对比之前的版本有了极大的改进，同时也被命名为 HTTP/1.0。与 HTTP/0.9 只能返回 HTML 不同的是，HTTP/1.0 支持处理多种返回的格式，比如图片、视频、文本或者其他格式的文件。它还增加了更多的请求方法（如 POST 和 HEAD），请求和响应的格式也相应做了改变，两者都增加了头信息；引入了状态码来定义返回的特征；引入了字符集支持；支持 多段类型 （ multi-part ） 、用户验证信息、缓存、内容编码格式等等。一个简单的 HTTP/1.0 请求大概是这样的：GET / HTTP/1.0 Host: kamranahmed.info User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) Accept: */* 正如你所看到的，在请求中附带了客户端中的一些个人信息、响应类型要求等内容。这些是在 HTTP/0.9 无法实现的，因为那时候没有头信息。一个对上述请求的响应例子如下所示：HTTP/1.0 200 OK Content-Type: text/plain Content-Length: 137582 Expires: Thu, 05 Dec 1997 16:00:00 GMT Last-Modified: Wed, 5 August 1996 15:55:28 GMT Server: Apache 0.84 (response body) (connection closed) 从 HTTP/1.0 （HTTP 后面跟的是版本号）早期开始，在状态码 200 之后就附带一个原因短语（你可以用来描述状态码）。在这个较新一点的版本中，请求和响应的头信息仍然必须是 ASCII 编码，但是响应的内容可以是任意类型，如图片、视频、HTML、文本或其他类型，服务器可以返回任意内容给客户端。所以这之后，HTTP 中的“ 超文本 （ Hyper Text ） ”成了名不副实。 HMTP （ 超媒体传输协议 （ Hypermedia transfer protocol ） ）可能会更有意义，但是我猜我们还是会一直沿用这个名字。HTTP/1.0 的一个主要缺点就是它不能在一个连接内拥有多个请求。这意味着，当客户端需要从服务器获取东西时，必须建立一个新的 TCP 连接，并且处理完单个请求后连接即被关闭。需要下一个东西时，你必须重新建立一个新的连接。这样的坏处在哪呢？假设你要访问一个有 10 张图片，5 个 样式表 （ stylesheet ） 和 5 个 JavaScript 的总计 20 个文件才能完整展示的一个页面。由于一个连接在处理完成一次请求后即被关闭，所以将有 20 个单独的连接，每一个文件都将通过各自对应的连接单独处理。当连接数量变得庞大的时候就会面临严重的性能问题，因为 TCP 启动需要经过三次握手，才能缓慢开始。三次握手三次握手是一个简单的模型，所有的 TCP 连接在传输应用数据之前都需要在三次握手中传输一系列数据包。SYN - 客户端选取一个随机数，我们称为 x，然后发送给服务器。SY…

如何在 CentOS 7 用 cPanel 配置 Nginx 反向代理
type: item
date: 2016-09-07T14:34:00+08:00
description: Nginx 是最快和最强大的 Web 服务器之一，以其高性能和低资源占用率而闻名。它既可以被安装为一个独立的 Web 服务器，也可以安装成反向代理 Web 服务器。在这篇文章，我将讨论在安装了 cPanel 管理系统的 Centos 7 服务器上安装 Nginx 作为 Apache 的反向代理服务器。Nginx 作为前端服务器用反向代理为静态文件提供服务，Apache 作为后端为动态文件提供服务。这个设置将整体提高服务器的性能。让我们过一遍在已经安装好 cPanel 11.52 的 CentOS 7 x86\_64 服务器上配置 Nginx 作为反向代理的安装过程。首先，我们需要安装 EPEL 库来启动这个进程第一步: 安装 EPEL 库root@server1 [/usr]# yum -y install epel-release Loaded plugins: fastestmirror, tsflags, universal-hooks Loading mirror speeds from cached hostfile * EA4: 66.23.237.210 * base: mirrors.linode.com * extras: mirrors.linode.com * updates: mirrors.linode.com Resolving Dependencies --> Running transaction check ---> Package epel-release.noarch 0:7-5 will be installed --> Finished Dependency Resolution Dependencies Resolved ======================================================================================== Package Arch Version Repository Size ======================================================================================== Installing: epel-release noarch 7-5 extras 14 k 第二步: 可以安装 nDeploy 的 CentOS RPM 库来安装我们所需的 nDeploy Web 类软件和 Nginx 插件root@server1 [/usr]# yum -y install http://rpm.piserve.com/nDeploy-release-centos-1.0-1.noarch.rpm Loaded plugins: fastestmirror, tsflags, universal-hooks nDeploy-release-centos-1.0-1.noarch.rpm | 1.7 kB 00:00:00 Examining /var/tmp/yum-root-ei5tWJ/nDeploy-release-centos-1.0-1.noarch.rpm: nDeploy-release-centos-1.0-1.noarch Marking /var/tmp/yum-root-ei5tWJ/nDeploy-release-centos-1.0-1.noarch.rpm to be installed Resolving Dependencies --> Running transaction check ---> Package nDeploy-release-centos.noarch 0:1.0-1 will be installed --> Finished Dependency Resolution Dependencies Resolved ======================================================================================== Package Arch Version Repository Size ======================================================================================== Installing: nDeploy-release-centos noarch 1.0-1 /nDeploy-release-centos-1.0-1.noarch 110 第三步：安装 nDeploy 和 Nginx nDeplo…

搭个 Web 服务器（二）
type: item
date: 2016-08-16T17:33:00+08:00
description: 在第一部分中，我提出了一个问题：“如何在你刚刚搭建起来的 Web 服务器上适配 Django, Flask 或 Pyramid 应用，而不用单独对 Web 服务器做做出改动以适应各种不同的 Web 框架呢？”我们可以从这一篇中找到答案。曾几何时，你所选择的 Python Web 框架会限制你所可选择的 Web 服务器，反之亦然。如果某个框架及服务器设计用来协同工作的，那么一切正常：但你可能正面对着（或者曾经面对过）尝试将一对无法适配的框架和服务器搭配在一起的问题：基本上，你需要选择那些能够一起工作的框架和服务器，而不能选择你想用的那些。所以，你该如何确保在不对 Web 服务器或框架的代码做任何更改的情况下，让你的 Web 服务器和多个不同的 Web 框架一同工作呢？这个问题的答案，就是 Python Web 服务器网关接口 （ Web Server Gateway Interface ） （缩写为 WSGI，念做“wizgy”）。WSGI 允许开发者互不干扰地选择 Web 框架及 Web 服务器的类型。现在，你可以真正将 Web 服务器及框架任意搭配，然后选出你最中意的那对组合。比如，你可以使用 Django，Flask 或者 Pyramid，与 Gunicorn，Nginx/uWSGI 或 Waitress 进行结合。感谢 WSGI 同时对服务器与框架的支持，我们可以真正随意选择它们的搭配了。所以，WSGI 就是我在第一部分中提出，又在本文开头重复了一遍的那个问题的答案。你的 Web 服务器必须实现 WSGI 接口的服务器部分，而现代的 Python Web 框架均已实现了 WSGI 接口的框架部分，这使得你可以直接在 Web 服务器中使用任意框架，而不需要更改任何服务器代码，以对特定的 Web 框架实现兼容。现在，你已经知道 Web 服务器及 Web 框架对 WSGI 的支持使得你可以选择最合适的一对来使用，而且它也有利于服务器和框架的开发者，这样他们只需专注于其擅长的部分来进行开发，而不需要触及另一部分的代码。其它语言也拥有类似的接口，比如：Java 拥有 Servlet API，而 Ruby 拥有 Rack。这些理论都不错，但是我打赌你在说：“Show me the code!” 那好，我们来看看下面这个很小的 WSGI 服务器实现：### 使用 Python 2.7.9，在 Linux 及 Mac OS X 下测试通过 import socket import StringIO import sys class WSGIServer(object): address_family = socket.AF_INET socket_type = socket.SOCK_STREAM request_queue_size = 1 def __init__(self, server_address): ### 创建一个监听的套接字 self.listen_socket = listen_socket = socket.socket( self.address_family, self.socket_type ) ### 允许复用同一地址 listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ### 绑定地址 listen_socket.bind(server_address) ### 激活套接字 listen_socket.listen(self.request_queue_size) ### 获取主机的名称及端口 host, port = self.listen_socket.getsockname()[:2] self.server_name = socket.getfqdn(host) self.server_port = port ### 返回由 Web 框架/应用设定的响应头部字段 self.headers_set = [] def set_app(self, application): self.application = application def serve_forever(self): listen_socket = self.listen_socket while True: ### 获取新的客户端连接 self.client_connection, client_address = listen_socket.accept() ### 处理一条请求后关闭连接，然后循环等待另一个连接建立 self.handle_one_request() def handle_one_request(self): self.reques…