Go Web编程(txt+pdf+epub+mobi电子书下载)


发布时间:2020-05-24 23:03:47

点击下载

作者:郑兆雄

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Go Web编程

Go Web编程试读:

前言

原文为例,其中就有一句“My own journey in developing applications for the web started around the same time, in the mid-1990s”,这句话的原意是说作者的Web开发生涯跟万维网的发展轨迹正好重合,因此把它单纯地译为“本人的Web应用开发生涯也是从20世纪90年代中期开始……”是完全没有问题的,但是通过在句子前面添加“无独有偶”一词来与“around the same time”的翻译“也是”相互呼应,就会一下子给译文带来画龙点睛的效果:“无独有偶,本人的Web应用开发生涯也是从20世纪90年代中期开始……”

继续以前言为例,在这篇文章的原文当中,出现了不少常见的英文短语和词汇,这些短语和词汇通常都有一个正确、常见并且平庸的翻译,但是本书却抛弃了这些翻译,转而选择了更准确也更有表现力的译法。比如说,“Writing web applications has changed dramatically over the years”中的“changed dramatically”没有直译为“发生了戏剧性的变化”,而是翻译为“发生了翻天覆地的变化”;“Almost as soon as the first web applications were written, web application frameworks appeared”中的“were written”和“appeared”没有直译为“被编写出来之后”以及“出现”,而是分别翻译为“闪亮登场”和“应运而生”,前者突出了Web应用的出现对于互联网的巨大改变,而后者则突出了Web应用和Web框架之间相辅相成的关系。类似的例子还有很多很多,并且它们不仅出现在了前言里,还出现在了本书的正文当中。

当然,提高译文的可读性并不是一件一蹴而就的事。为了让译文更有“中文味”,本书的大多数译文都已三易其稿,有时候仅仅为了挑选出一个更恰当的词语或成语,就不得不对着词典推敲半天。这本书的翻译从2016年8月开始,到2017年8月交稿,整整跨越了一年时间,其中翻译原文和润色译文两项工作花费的时间可谓各占一半。如果读者能够从译文的字里行间感受到这种润物细无声的优化,那将是对本人翻译工作最好的肯定。

另外,因为这是一本使用Go语言标准库进行Web开发的书,所以对Go Web开发相关标准库的理解程度将是能否准确地翻译本书技术内容的关键。为了进一步熟悉本书用到的标准库,本人通读了书中用到的各个标准库的文档,阅读了其中部分标准库的源码,并且因为有时候“好记性比不上烂笔头”,所以本人还翻译了其中一部分标准库文档,力求在尽可能掌握标准库细节的情况下,再进行翻译,尽量做到知其然也知其所以然,而不是单纯地根据纸面上的文字和代码进行翻译。

最后,在翻译本书的过程中,本人也发现了原著中大大小小数十个bug,并在译文中一一进行了修正。综上所述,读者看到的这个译本从某个角度来说将比原著更准确也更易读。这也是我一直以来在实践翻译工作时的信念——译作不应该是原著的“劣化版”,而是应该以“青出于蓝而胜于蓝”的方式超越原著。当然,要做到这一点并不是一件容易的事,但每一个合格的译者都应该以此为目标,不断奋斗。读者服务网站

为了更好地服务本书读者,本人专门为本书搭建了读者服务网站http://gwpcn.com。读者只要访问这个网站,就可以查看到与本书有关的各项信息,如本书的简介、目录、试读内容、作译者介绍、勘误信息、购买地址以及源代码下载地址等。

除此之外,正如之前所说,本人在翻译本书的过程中也翻译了一部分Go标准库的文档,这些文档可以通过地址http://cngolib.com查看。致谢

感谢人民邮电出版社以及杨海玲编辑对我的信任,将这样一本有趣而且重要的书交给我翻译,我衷心希望这本译作能够取得好成绩,从而不辜负他们对我的信任与期待。

感谢网络上一直关心这个译本出版进度的读者朋友们,他们的支持和鼓励让我不敢有所怠慢,争取竭尽自己所能,贡献出一个能够为大家所喜爱的译本。

最后也是最重要的,我要感谢本书翻译过程中一如既往地全力支持我的家人和朋友,多亏了他们的帮助,本书的翻译工作才得以顺利完成。黄健宏2017年秋译者简介

黄健宏(huangz),一位1990年出生的计算机技术图书作译者,《Redis设计与实现》一书的作者,《Redis实战》一书的译者。

除了已出版的两本作品之外,他还创作和翻译了《Go标准库中文文档》《Redis命令参考》《SICP解题集》等一系列开源文档。

要了解关于黄健宏的更多信息,请访问他的个人主页http://huangz.me。前言

自互联网从20世纪90年代中期诞生以来,Web应用就以这样或那样的方式存在了。虽然Web应用在最初只能传输静态网页,但它很快就升级和演变成了一个令人眼花缭乱、能够传输各种数据以及实现各种功能的动态系统。无独有偶,本人也是从20世纪90年代中期开始接触Web应用开发的,在迄今为止的职业生涯当中,我把大部分时间都花费在了大规模Web应用的设计、开发以及团队管理上面,并且在这期间还使用过多种不同的编程语言和框架,其中包括Java、Ruby、Node.js、PHP、Perl、Elixir甚至是Smalltalk。

几年前,我因为一次偶然的机会接触到了Go语言,并迅速被它的简单和清爽直率所吸引,而当我意识到只使用Go的标准库就可以快速地构建完整、高效并且可扩展的Web应用和服务时,我对Go的喜爱又更进了一步。使用Go语言编写的代码不仅易懂、直截了当,而且还能够快速、简单地编译成一个独立的可部署二进制文件。更关键的是,我不必投入大量服务器就可以让自己的Web应用变得可扩展且具备生产能力。很自然地,所有的这些优点都使Go成为了我在Web应用开发方面最新的心头好语言。

从当初传输静态内容到现在通过HTTP传输动态数据,从当初使用服务器传输HTML内容,到现在使用客户端单页应用去处理通过HTTP传输的JSON数据,Web应用的开发方式已经发生了翻天覆地的变化。几乎就在Web应用闪亮登场的同时,Web框架也应运而生,并使程序员可以更为容易地去开发Web应用。这二十多年以来,绝大多数编程语言都会有至少一个Web应用框架,其中很多语言甚至会有一大堆框架可用,而当今出现的绝大多数应用都是Web应用。

尽管Web应用框架的风靡使开发Web应用变得更加容易了,但这些框架在带来方便的同时也隐藏了大量的细节——Web应用开发者对于万维网的运作方式知之甚少甚至一窍不通,这样的情况正在变得越来越常见。幸运的是,通过Go语言,我发现了一种正确地教授Web应用开发基础知识的绝佳工具,它能够让Web应用开发重新回到简单直接的状态:程序需要考虑的就是如何处理HTTP协议,以及如何通过HTTP协议传输内容和数据,并且满足这两个要求只需要用到Go语言本身提供的工具——不需要用到外部库,也不需要用到外部的依赖。

在拿定注意之后,我就向Manning出版社提交了一个撰写Go语言编程书籍的构思,这个构思关注的是如何在只使用标准库的情况下,向读者传授从零开始构建Web应用的方法,而Manning出版社也很快就同意了我的构思并开启了这个项目。尽管本书的撰写工作持续了一段时间才得以完成,但是在写作的过程中,抢先预览版带来的反馈总是不断地鼓舞着我。最后,我希望读者能够像我享受创作本书的过程一样,享受阅读本书的过程,并且在这个过程中能够有所收获。致谢

本书最初的想法是在只使用标准库的情况下教授基本的Go Web编程知识。说实在的,刚开始的时候我并不确定这个想法是否能够行得通,但那些花费自己血汗钱来购买本书抢先预览版的读者给了我鼓励和动力来实现这个想法,因此在这里我要向我的读者们致以诚挚的感谢!

写书是一项团队协作活动,尽管本书的封面上只记载了我一个人的名字,但实际上大量幕后人员也为这本书付出了自己的心血,他们分别是:● Marina Michaels,来自地球另一侧的一位勤劳且高效的编

辑,她总是不知疲倦地配合我的工作,并且为了我们之间巨大的

时差而不断地调整自己的日程表;● Manning出版社的相关工作人员:文字编辑Liz Welch和校对

Elizabeth Martin,他们的火眼金睛让错误无处可藏,负责营销和

推广本书的Candace Gillhoolley和Ana Romac,以及将我的原稿

变为本书的Kevin Sullivan和Janet Vail;● Jimmy Frasché对我的原稿进行了一次完整的技术校对,而

我的审稿人Alex Jacinto、Alexander Schwartz、Benoit

Benedetti、Brian Cooksey、Doug Sparling、Ferdinando

Santacroce、Gualtiero Testa、Harry Shaun Lippy、James Tyo、

Jeff Lim、Lee Brandt、Mike Bright、Quintin Smith、Rebecca

Jones、Ryan Pulling、Sam Zaydel和Wes Shaddix则在撰写原稿

的4个阶段中为我提供了大量有价值的反馈;● 这本书的抢先预览版一经释出,我在新加坡Go社区的朋友

们就迫不及待地把它向全世界广而告之了,特别值得一提的是

Kai Hendry,他为本书制作了一个详细的评论视频。

另外,我还要感谢Go的创造者Robert Griesemer、Rob Pike和Ken Thompson,以及net/http、html/template等Web标准库的开发者,特别是Brad Fitzpatrick,没有他们的辛勤付出,这本书就不可能出现。

最后,也是最必不可少的,我要感谢我的家人,包括我亲爱的妻子Wooi Ying,以及在身高方面后来居上的我的儿子Kai Wen。我希望自己能够通过创作这本书给他带来启发,我也希望他会自豪地阅读这本书,并从中有所收获。关于本书

本书将完整地介绍使用Go语言开发Web应用所需的全部基本概念,并且在这个过程中只使用Go语言自带的标准库。尽管本书的部分章节会对其他库以及其他主题进行讨论,比如如何测试Web应用以及如何部署Web应用,但本书的主要目的还是教读者如何在只使用Go标准库的情况下进行Web开发。

本书要求读者具备基本的Go编程技能并掌握Go语言的语法。如果读者不具备这些知识,可以阅读由William Kennedy、Brian [1]Ketelsen和Erik St. Martin创作的Go in Action一书,该书也是由Manning出版社出版的。由Addison-Wesley 出版社出版、Alan [2]Donovan和Brian Kernighan 创作的The Go Programming Language也是一本值得一读的好书。除了以上提到的两本书之外,网上也有非常多免费的Go教程可供浏览,比如,Go官方网站的《Go入门教程》(A Tour of Go)(http://tour.golang.org/)就是一个很棒的例子。内容编排

本书由10章和一个附录组成。

第1章会介绍使用Go开发Web应用的方法,并阐述这种做法的优点所在。除此之外,本章还会对HTTP协议等构成Web应用的关键概念做深入浅出的介绍。

第2章会以一步一个脚印的方式,带领读者去构建一个简单的网上论坛,以此来向读者展示如何使用Go构建一个典型的Web应用。

第3章会更加详细地展示使用net/http包接收HTTP请求的方法。读者将学会如何编写Go Web服务器监听HTTP请求,以及如何使用处理器和处理器函数处理这些请求。

第4章会继续介绍处理HTTP请求的相关细节,重点讲述Go是如何处理请求并返回响应的。除此之外,读者还将学会如何从HTML表单中获取数据以及如何使用cookie。

第5章将会介绍由text/template库和html/template库组成的Go模板引擎。读者将会看到Go提供的各种模板机制,并学会如何使用Go的布局(layout)。

第6章将会对Go的存储策略进行讨论。读者将学会如何通过结构将数据存储到内存里面,如何通过CSV格式以及gob二进制格式将数据存储到文件系统里面,以及如何通过SQL和SQL映射器去访问关系数据库。

第7章将展示使用Go语言构建Web服务的方法。读者不仅会学到如何使用Go语言构建一个简单的Web服务,还会学到如何使用Go语言创建并分析XML数据和JSON数据。

第8章将向读者传授在不同层级中测试Go Web应用的不同方法,其中包括单元测试、基准测试以及HTTP测试;除此之外,这一章还会简单介绍几个第三方测试库。

第9章会介绍在Web应用中使用Go语言的并发特性的方法。读者将会了解到Go语言的各个并发特性,并学会如何使用这些特性提高一个图像生成Web应用的性能。

第10章是本书的最后一章,它将展示Go Web应用的部署方法。读者将会学到如何把应用部署到独立的服务器上,如何把应用部署到Heroku、Google App Engine之类的云平台上,以及如何把应用部署到Docker容器里面。

最后,本书的附录会展示在不同平台上安装和设置Go环境的方法。代码的约定以及下载

本书通过代码清单以及正文内嵌的方式展示了大量源代码。为了跟一般的正文区别开来,书中的源代码都会使用等宽字体。为了凸显某些代码在不同章节之间的区别,又或者为了强调正文中讨论的某些代码,本书有时候也会以加粗的方式显示代码。

除此之外,本书的电子书还会使用彩色字体来凸显代码命令以及代码输出:curl -i 127.0.0.1:8080/writeHTTP/1.1 200 OKDate: Tue, 13 Jan 2015 16:16:13 GMT Content-Length: 95Content-Type: text/html; charset=utf-8Go Web Programming

Hello World

本书展示的所有代码都可以在www.manning.com/books/go-web-[3]programming 和 github.com/ sausheong/gwp找到。作者简介

郑兆雄(Sau Sheong Chang),现任新加坡能源有限公司数字技术总裁,在此之前他曾经担任过PayPal的消费者工程经理。Sau是Ruby社区和Go社区一位活跃的贡献者,除了创作书籍之外,他还为开源项目提交代码,并在各种技术研讨会和技术会议上发言。作者在线论坛

购买本书英文版的读者可以免费地访问由Manning出版社开设的私有Web论坛,可以在论坛里面撰写书评、提出技术问题并接受来自作者和其他读者的帮助。为了访问并订阅论坛,需要先使用浏览器访问www.manning.com/books/go-web-programming,这个页面会告诉读者注册账号和访问论坛的方法,除此之外,该页面还列举了论坛提供的各种帮助以及论坛的各项规章制度。

Manning出版社承诺为读者提供论坛作为场所,以便读者之间以及读者和作者之间可以进行有意义的对话,但Manning并不保证作者的参与程度——作者对论坛的任何贡献都是自愿并且无偿的,因此读者应该尽可能地提出一些具有挑战性的问题以便引起作者的兴趣。

只要本书仍在正常销售,本书的作者在线论坛以及论坛上已有的帖子就会一直可供访问。[1] Go in Action的中文版已由人民邮电出版社出版,中文版书名为《Go语言实战》。——译者注[2] The Go Programming Language的中文版已由机械工业出版社出版,中文版书名为《Go程序设计语言》。——译者注[3] 本书展示的所有代码也可以在异步社区(www.epubit.com.cn)中本书页面免费下载。——编者注关于封面插图

本书的封面插图系Paolo Mercuri(1804—1884)所作,标题为“穿着中世纪服装的男人”,该插图来源于Camille Bonnard搜集并编辑的Costumes Historiques(服装史)多卷本,该书于19世纪50或60年代在巴黎出版,它搜集了大量12世纪、13世纪、14世纪和15世纪的历史服装。随着异国风情和历史文明在19世纪风靡,人们开始着迷于这类服装收藏本,并藉此去探索自己所在的世界以及已经远去的旧世界。

在这一历史画册中,Mercuri丰富多彩的画作让我们生动地回想起了数百年前,世界各地不同城市和地区之间的文化差异。无论是在街道还是乡间,仅仅通过人们的着装就可以八九不离十地辨识他们的社会地位、从事的行业和职业。在经历了数个世纪的变迁以后,人们的着装方式已经发生了很大的变化,当初丰富多彩的地区多样性也已逐渐消失。时至今日,仅仅通过着装已经很难区分不同大洲的居民了,更别说想要知道他们所在的国家和城市、知悉他们的社会地位和职业了。乐观地讲,也许我们已经放弃了追求文化上的多样性,转为拥抱更丰富多彩也更快节奏的技术生活了。

在计算机书籍正在变得越来越相似、越来越同质化的今天,Manning出版社希望通过Mercuri的作品,将数个世纪以前丰富多彩的地区生活融入图书封面,以此来赞美计算机行业不断创新和敢为人先的精神。第一部分 Go与Web应用

Web应用是当今使用最为广泛的一类软件应用,连接至互联网的人们基本上每天都在使用Web应用。因为很多看上去像是原生应用的移动应用都在内部包含了使用Web技术构建的组件,所以使用移动设备的人们实际上也是在使用Web应用。

因为编写Web应用必须对HTTP有所了解,所以接下来的两章将对HTTP进行介绍。除此之外,我们还会了解到使用Go语言编写Web应用的优点,并且实际使用Go语言来构建一个简单的网上论坛,然后鸟瞰Web应用的各个组成部分。第1章 Go与Web应用本章主要内容● Web应用的定义● 使用Go语言编写Web应用的优点● Web应用编程的基本知识● 使用Go语言编写一个极为简单的Web应用

Web应用在我们的生活中无处不在。看看我们日常使用的各个应用程序,它们要么是Web应用,要么是移动App这类Web应用的变种。无论哪一种编程语言,只要它能够开发出与人类交互的软件,它就必然会支持Web应用开发。对一门崭新的编程语言来说,它的开发者首先要做的一件事,就是构建与互联网(internet)和万维网(World Wide Web)交互的库(library)和框架,而那些更为成熟的编程语言还会有各种五花八门的Web开发工具。

Go是一门刚开始崭露头角的语言,它是为了让人们能够简单且高效地编写后端系统(back end system)而创建的。这门语言拥有众多先进的特性,并且密切关注程序员的生产力以及各种与速度相关的事项。和其他语言一样,Go语言也提供了对Web编程的支持。自从问世以来,Go语言在编写Web应用以及“×即服务系统”(*-as-a-service system)方面就受到了热烈追捧。

本章接下来将列举一些使用Go编写Web应用的优点,并介绍一些关于Web应用的基本知识。1.1 使用Go语言构建Web应用“为什么要使用Go语言编写Web应用呢?”作为本书的读者,我想你肯定很想知道这个问题的答案。本书是一本教人们如何使用Go语言进行Web编程的图书,而作为本书的作者,我的任务就是向你解释为什么人们会使用Go语言进行Web编程。本书将在接下来的内容中陆续介绍Go语言在Web开发方面的优点,我衷心地希望你也能够对这些优点有感同身受的想法。

Go是一门相对比较年轻的编程语言,它拥有繁荣并且仍在不断成长的社区,并且它也非常适合用来编写那些需要快速运行的服务器端程序。因为Go语言提供了很多过程式编程语言的特性,所以拥有过程式编程语言使用经验的程序员对Go应该都不会感到陌生,但与此同时,Go语言也提供了函数式编程方面的特性。除了内置对并发编程的支持之外,Go语言还拥有现代化的包管理系统、垃圾收集特性以及一系列包罗万象、威力强大的标准库。

虽然Go自带的标准库已经非常丰富和宏大了,但Go仍然拥有许多质量上乘的开源库,它们可以对标准库不足的地方进行补充。本书在大部分情况下都会尽可能地使用标准库,但是偶尔也会使用一些第三方开源库,以此来展示开源社区提供的一些另辟蹊径并且富有创意的方法。

使用Go语言进行Web开发正变得日益流行,很多公司都已经开始使用Go了,其中包括Dropbox、SendGrid这样的基础设施公司,Square和Hailo这样的技术驱动的公司,甚至是BBC、纽约时报这样的传统公司。

在开发大规模Web应用方面,Go语言提供了一种不同于现有语言和平台但又切实可行的方案。大规模可扩展的Web应用通常需要具备以下特质:● 可扩展;● 模块化;● 可维护;● 高性能。

接下来的几小节将分别对这些特质进行讨论。1.1.1 Go与可扩展Web应用

大规模的Web应用应该是可扩展的(scalable),这意味着应用的管理者应该能够简单、快速地提升应用的性能以便处理更多请求。如果一个应用是可扩展的,那么它就是线性的,这意味着应用的管理者可以通过添加更多硬件来获得更强的请求处理能力。

有两种方式可以对性能进行扩展:● 一种是垂直扩展(vertical scaling),即提升单台设备的CPU数量

或者性能;● 另一种则是水平扩展(horizontal scaling),即通过增加计算机的

数量来提升性能。

因为Go语言拥有非常优异的并发编程支持,所以它在垂直扩展方面拥有不俗的表现:一个Go Web应用只需要使用一个操作系统线程(OS thread),就可以通过调度来高效地运行数十万个goroutine。

跟其他Web应用一样,Go也可以通过在多个Go Web应用之上架设代理来进行高效的水平扩展。因为Go Web应用都会被编译为不包含任何动态依赖关系的静态二进制文件,所以我们可以把这些文件分发到没有安装Go语言的系统里,从而以一种简单且一致的方式部署Go Web应用。1.1.2 Go与模块化Web应用

大规模Web应用应该由可替换的组件构成,这种做法能够使开发者更容易添加、移除或者修改特性,从而更好地满足程序不断变化的需求。除此之外,这种做法的另一个好处是使开发者可以通过复用模块化的组件来降低软件开发所需的费用。

尽管Go是一门静态类型语言,但用户可以通过它的接口机制对行为进行描述,以此来实现动态类型匹配(dynamic typing)。Go语言的函数可以接受接口作为参数,这意味着用户只要实现了接口所需的方法,就可以在继续使用现有代码的同时向系统中引入新的代码。与此同时,因为Go语言的所有类型都实现了空接口,所以用户只需要创建出一个接受空接口作为参数的函数,就可以把任何类型的值用作该函数的实际参数。此外,Go语言还实现了一些在函数式编程中非常常见的特性,其中包括函数类型、使用函数作为值以及闭包,这些特性允许用户使用已有的函数来构建新的函数,从而帮助用户构建出更为模块化的代码。

Go语言也经常会被用于创建微服务(microservice)。在微服务架构中,大型应用通常由多个规模较小的独立服务组合而成,这些独立服务通常可以相互替换,并根据它们各自的功能进行组织。比如,日志记录服务会被归类为系统级服务,而开具账单、风险分析这样的服务则会被归类为应用级服务。创建多个规模较小的Go服务并将它们组合为单个Web应用,这种做法使得我们可以在有需要的时候对应用中的服务进行替换,而整个Web应用也会因此变得更加模块化。1.1.3 Go与可维护的Web应用

和其他庞大而复杂的应用一样,拥有一个易于维护的代码库(codebase)对大规模的Web应用来说也是非常重要的。这是因为大规模的应用通常都会不断地成长和演化,所以开发者需要经常性地回顾并修改代码,而修改难懂、笨拙的代码需要花费大量的时间,并且隐含着可能会造成某些功能无法正常运作的风险。因此,确保源代码能够以适当的方式组织起来并且具有良好的可维护性对开发者来说就显得至关重要了。

Go语言的设计鼓励良好的软件工程实践,它拥有简洁且极具可读性的语法以及灵活且清晰的包管理系统。除此之外,Go语言还有一整套优秀的工具,它们不仅可以增强程序员的开发体验,还能够帮助他们写出更具可读性的代码,比如以标准化方式对Go代码进行格式化的源代码格式化程序gofmt就是其中一个例子。

因为Go语言希望文档可以和代码一同演进,所以它的文档工具godoc会对Go源代码及其注释进行语法分析,然后以HTML、纯文本或者其他多种格式创建出相应的文档。godoc的使用方法非常简单,开发者只需要把文档写到源代码里面,godoc就会把这些文档以及与之相关联的代码提取出来,生成相应的文档文件。

除此之外,Go还内置了对测试的支持:gotest工具会自动寻找与源代码处于同一个包(package)之内的测试代码,并运行其中的功能测试和性能测试。Go语言也提供了Web应用测试工具,这些工具可以模拟出一个Web服务器,并对该服务器生成的响应(response)进行记录。1.1.4 Go与高性能Web应用

高性能不仅意味着能够在短时间内处理大量请求,还意味着服务器能够快速地对客户端进行响应,并让终端用户(end user)能够快速地执行操作。

Go语言的一个设计目标就是提供接近于C语言的性能,尽管这个目标目前尚未达成,但Go语言现在的性能已经非常具有竞争力:Go程序会被编译为本地码(native code),这一般意味着Go程序可以运行得比解释型语言的程序要快,并且就像前面说过的那样,Go语言的goroutine对并发编程提供了非常好的支持,这使得Go应用可以同时处理多个请求。

希望以上介绍能够引起你对使用Go语言及其平台进行Web开发的兴趣。但是在学习如何使用Go进行Web开发之前,我们需要先来了解一下什么是Web应用,以及它们的工作原理是什么,这会给我们学习之后几章的内容带来非常大的帮助。1.2 Web应用的工作原理

如果你在一个技术会议上向在场的程序员们提出“什么是Web应用”这一问题,那么通常会得到五花八门的回答,有些人甚至可能还会因为你问了个如此基础的问题而感到惊讶和不解。通过不同的人对这个问题的不同回答,我们可以了解到人们对Web应用并没有一个十分明确的定义。比如说,Web服务算不算Web应用?因为Web服务通常会被其他软件调用,而Web应用则是为人类提供服务,所以很多人都认为Web服务与Web应用是两种不同的事物。但如果一个程序能够像RSS feed那样,产生出来的数据既可以被其他软件使用,又可以被人类理解,那么这个程序到底是一个Web服务还是一个Web应用呢?

同样地,如果一个应用只会返回HTML页面,但却并不对页面进行任何处理,那么它是一个Web应用吗?运行在Web浏览器之上的Adobe Flash程序是一个Web应用吗?对于一个纯HTML5编写的应用,如果它运行在一个长期驻留于电脑的浏览器中,那么它算是一个Web应用吗?如果一个应用在向服务器发送请求时没有使用HTTP协议,那么它算是一个Web应用吗?大多数程序员都能够从高层次的角度去理解Web应用是什么,但是一旦我们深入一些,尝试去探究Web应用的实现层次,事情就会变得含糊不清起来。

从纯粹且狭隘的角度来看,Web应用应该是这样的计算机程序:它会对客户端发送的HTTP请求做出响应,并通过HTTP响应将HTML回传至客户端。但这样一来,Web应用不就跟Web服务器一样了吗?的确如此,如果按照上面给出的定义来看,Web服务器和Web应用将没有区别:一个Web服务器就是一个Web应用(如图1-1所示)。图1-1 Web应用最基本的请求与响应结构

将Web服务器看作是Web应用的一个问题在于,像httpd和Apache这样的Web服务器都会监视特定的目录,并在接收到请求时返回位于该目录中的文件(比如Apache就会对docroot目录进行监视)。与此相反,Web应用并不会简单地返回文件:它会对请求进行处理,并执行应用程序中预先设定好的操作(如图1-2所示)。图1-2 Web应用的工作原理

从以上观点来看,我们也许可以把Web服务器看作是一种特殊的Web应用,这种应用只会返回被请求的文件。普遍来讲,很多用户都会把使用浏览器作为客户端的应用看作是Web应用。这其中包括Adobe Flash应用、单页Web应用,甚至是那些不使用HTTP协议进行通信但却驻留在桌面或系统上的应用。

为了在书中讨论Web编程的相关技术,我们必须给这些技术一个明确的定义。首先,让我们来给出应用的定义。

应用(application)是一个与用户进行互动并帮助用户执行指定活动的软件程序。比如记账系统、人力资源系统、桌面出版软件等。而Web应用则是部署在Web之上,并通过Web来使用的应用。

换句话说,一个程序只需要满足以下两个条件,我们就可以把它看作是一个Web应用:● 这个程序必须向发送命令请求的客户端返回HTML,而客户端则

会向用户展示渲染后的HTML;● 这个程序在向客户端传送数据时必需使用HTTP协议。

在这个定义的基础上,如果一个程序不是向用户渲染并展示HTML,而是向其他程序返回某种非HTML格式的数据,那么这个程序就是一个为其他程序提供服务的Web服务。本书将在第7章对Web服务进行更详细的说明。

与大部分程序员对Web应用的定义相比,上面给出的定义可能显得稍微狭隘了一些,但因为这个定义消除了所有的模糊与不清晰,并使Web应用变得更加易于理解,所以它对于本书讨论的问题是非常有帮助的。随着读者对本书阅读的不断深入,这一定义将变得更为清晰,但是在此之前,让我们先来回顾一下HTTP协议的发展历程。1.3 HTTP简介

HTTP是万维网的应用层通信协议,Web页面中的所有数据都是通过这个看似简单的文本协议进行传输的。HTTP非常朴素,但却异常地强大——这个协议自20世纪90年代定义以来,至今只进行了3次迭代修改,其中HTTP 1.1是目前使用最为广泛的一个版本,而最新的一个版本则是HTTP 2.0,又称HTTP/2。

HTTP的最初版本HTTP 0.9是由Tim Berners-Lee为了让万维网能够得以被采纳而创建的:它允许客户端与服务器进行连接,并向服务器发送以空行(CRLF)结尾的ASCII字符串请求,而服务器则会返回不带任何元数据的HTML作为响应。

HTTP 0.9之后的每个新版本实现都包含了大量的新特性,1996年发布的HTTP 1.0就是由大量特性合并而成的,之后的HTTP 1.1版本于1999年发布,而HTTP 2.0版本则于2015年发布。因为目前使用最为广泛的还是HTTP 1.1版本,所以本书主要还是对HTTP 1.1进行讨论,但也会在适当的地方介绍一些HTTP 2.0的相关信息。

首先,让我们通过一个简单的定义来说明什么是HTTP。HTTP是一种无状态、由文本构成的请求-响应(request-response)协议,这种协议使用的是客户端-服务

器(client-server)计算模型。

请求-响应是两台计算机进行通信的基本方式,其中一台计算机会向另一台计算机发送请求,而接收到请求的计算机则会对请求进行响应。在客户端-服务器计算模型中,发送请求的一方(客户端)负责向返回响应的一方(服务器)发起会话,而服务器则负责为客户端提供服务。在HTTP协议中,客户端也被称作用户代理(user-agent),而服务器则通常会被称为Web服务器。在大多数情况下,HTTP客户端都是一个Web浏览器。

HTTP是一种无状态协议,它唯一知道的就是客户端会向服务器发送请求,而服务器则会向客户端返回响应,并且后续发生的请求对之前发生过的请求一无所知。相对的,像FTP、Telnet这类面向连接的协议则会在客户端和服务器之间创建一个持续存在的通信通道(其中Telnet在进行通信时使用的也是请求-响应方式以及客户端-服务器计算模型)。顺带提一下,HTTP 1.1也可以通过持久化连接来提升性能。

跟很多互联网协议一样,HTTP也是以纯文本方式而不是二进制方式发送和接收协议数据的。这样做是为了让开发者可以在无需使用专门的协议分析工具的情况下,弄清楚通信中正在发生的事情,从而更容易进行故障排查。

因为HTTP最初在设计时只用于传送HTML,所以HTTP 0.9只提供了GET这一个方法(method),但新版本对HTTP的扩展使它逐渐变成了一种通用的协议,用户也得以将其应用于Web应用等分布式系统中,本章接下来就会对Web应用进行介绍。1.4 Web应用的诞生

在万维网出现不久之后,人们开始意识到一点:尽管使用Web服务器处理静态HTML文件这个主意非常棒,但如果HTML里面能够包含动态生成的内容,那么事情将会变得更加有趣。其中,通用网关接口(Common Gateway Interface,CGI)就是在早期尝试动态生成HTML内容的技术之一。

1993年,美国国家超级计算应用中心(National Center for Supercomputing Applications, NCSA)编写了一个在Web服务器上调用可执行命令行程序的规范(specification),他们把这个规范命名为CGI,并将它包含在了NCSA开发的广受欢迎的HTTPd服务器里面。不过NCSA制定的这个规范最终并没有成为正式的互联网标准,只有CGI这个名字被后来的规范沿用了下来。

CGI是一个简单的接口,它允许Web服务器与一个独立运行于Web服务器进程之外的进程进行对接。通过CGI与服务器进行对接的程序通常被称为CGI程序,这种程序可以使用任何编程语言编写——这也是我们把这种接口称之为“通用”接口的原因,不过早期的CGI程序大多数都是使用Perl语言编写的。向CGI程序传递输入参数是通过设置环境变量来完成的,CGI程序在运行之后将向标准输出(stand output)返回结果,而服务器则会将这些结果传送至客户端。

与CGI同期出现的还有服务器端包含(server-side includes,SSI)技术,这种技术允许开发者在HTML文件里面包含一些指令(directive):当客户端请求一个HTML文件的时候,服务器在返回这个文件之前,会先执行文件中包含的指令,并将文件中出现指令的位置替换成这些指令的执行结果。SSI最常见的用法是在HTML文件中包含其他被频繁使用的文件,又或者将整个网站都会出现的页面首部(header)以及尾部(footer)的代码段嵌入HTML文件中。

作为例子,以下代码演示了如何通过SSI指令将navbar.shtml文件中的内容包含到HTML文件中: Example SSI    

SSI技术的最终演化结果就是在HTML里面包含更为复杂的代码,并使用更为强大的解释器(interpreter)。这一模式衍生出了PHP、ASP、JSP和ColdFusion等一系列非常成功的引擎,开发者通过使用这些引擎能够开发出各式各样复杂的Web应用。除此之外,这一模式也是Mustache、ERB、Velocity等一系列Web模板引擎的基础。

如前所述,Web应用是为了通过HTTP向用户发送定制的动态内容而诞生的,为了弄明白Web应用的运作原理,我们必须知道HTTP的工作过程,并理解HTTP请求和响应的运作机制。1.5 HTTP请求

HTTP是一种请求-响应协议,协议涉及的所有事情都以一个请求开始。HTTP请求跟其他所有HTTP报文(message)一样,都由一系列文本行组成,这些文本行会按照以下顺序进行排列:(1)请求行(request-line);(2)零个或任意多个请求首部(header);(3)一个空行;(4)可选的报文主体(body)。

一个典型的HTTP请求看上去是这个样子的:GET /Protocols/rfc2616/rfc2616.html HTTP/1.1Host: www.w3.orgUser-Agent: Mozilla/5.0(empty line)

这个请求中的第一个文本行就是请求行:GET /Protocols/rfc2616/rfc2616.html HTTP/1.1

请求行中的第一个单词为请求方法(request method),之后跟着的是统一资源标识符(Uniform Resource Identifier,URI)以及所用的HTTP版本。位于请求行之后的两个文本行为请求的首部。注意,这个报文的最后一行为空行,即使报文的主体部分为空,这个空行也必须存在,至于报文是否包含主体则需要根据请求使用的方法而定。1.5.1 请求方法

请求方法是请求行中的第一个单词,它指明了客户端想要对资源执行的操作。HTTP 0.9只有GET一个方法,HTTP 1.0添加了POST方法和HEAD方法,而HTTP 1.1则添加了PUT、DELETE、OPTIONS、TRACE和CONNECT这5个方法,并允许开发者自行添加更多方法——很多人立即就把这个功能付诸实践了。

关于请求方法的一个有趣之处在于,HTTP 1.1要求必须实现的只有GET方法和HEAD方法,而其他方法的实现则是可选的,甚至连POST方法也是可选的。

各个HTTP方法的作用说明如下。● GET——命令服务器返回指定的资源。● HEAD——与GET方法的作用类似,唯一的不同在于这个方法不

要求服务器返回报文的主体。这个方法通常用于在不获取报文主

体的情况下,取得响应的首部。● POST——命令服务器将报文主体中的数据传递给URI指定的资

源,至于服务器具体会对这些数据执行什么动作则取决于服务器

本身。● PUT——命令服务器将报文主体中的数据设置为URI指定的资

源。如果URI指定的位置上已经有数据存在,那么使用报文主体

中的数据去代替已有的数据。如果资源尚未存在,那么在URI指

定的位置上新创建一个资源。● DELETE——命令服务器删除URI指定的资源。● TRACE——命令服务器返回请求本身。通过这个方法,客户端

可以知道介于它和服务器之间的其他服务器是如何处理请求的。● OPTIONS——命令服务器返回它支持的HTTP方法列表。● CONNECT——命令服务器与客户端建立一个网络连接。这个方

法通常用于设置SSL隧道以开启HTTPS功能。● PATCH——命令服务器使用报文主体中的数据对URI指定的资源

进行修改。1.5.2 安全的请求方法

如果一个HTTP方法只要求服务器提供信息而不会对服务器的状态做任何修改,那么这个方法就是安全的(safe)。GET、HEAD、OPTIONS和TRACE都不会对服务器的状态进行修改,所以它们都是安全的方法。与此相反,POST、PUT和DELETE都能够对服务器的状态进行修改(比如说,在处理POST请求时,服务器存储的数据就可能会发生变化),因此这些方法都不是安全的方法。1.5.3 幂等的请求方法

如果一个HTTP方法在使用相同的数据进行第二次调用的时候,不会对服务器的状态造成任何改变,那么这个方法就是幂等的(idempotent)。根据安全的方法的定义,因为所有安全的方法都不会修改服务器状态,所以它们天生就是幂等的。

PUT和DELETE虽然不安全,但却是幂等的,这是因为它们在进行第二次调用时都不会改变服务器的状态:因为服务器在执行第一个PUT请求之后,URI指定的资源已经被更新或者创建出来了,所以针对同一个资源的第二次PUT请求只会执行服务器已经执行过的动作;与此类似,虽然服务器对于同一个资源的第二次DELETE请求可能会返回一个错误,但这个请求并不会改变服务器的状态。

相反,因为重复的POST请求是否会改变服务器状态是由服务器自身决定的,所以POST方法既不安全也非幂等。幂等性是一个非常重要的概念,本书第7章在介绍Web服务时将再次提及这个概念。1.5.4 浏览器对请求方法的支持

GET方法是最基本的HTTP方法,它负责从服务器上获取内容,所有浏览器都支持这个方法。POST方法从HTML 2.0 开始可以通过添加HTML表单来实现:HTML的form标签有一个名为method的属性,用户可以通过将这个属性的值设置为get或者post来指定要使用哪 种方法。

HTML不支持除GET和POST之外的其他HTTP方法:在HTML5规范的早期草案中,HTML表单的method属性曾经添加过对PUT方法和DELETE方法的支持,但这些支持在之后又被删除了。

话虽如此,但流行的浏览器通常都不会只支持HTML一种数据格式——用户可以使用XMLHttpRequest(XHR)来获得对PUT方法和DELTE方法的支持。XHR是一系列浏览器API,这些API通常由JavaScript包裹(实际上XHR就是一个名为XMLHttpRequest的浏览器对象)。XHR允许程序员向服务器发送HTTP请求,并且跟“XMLHttpRequest”这个名字所暗示的不一样,这项技术并不仅仅局限于XML格式——包括JSON以及纯文本在内的任何格式的请求和响应都可以通过XHR发送。1.5.5 请求首部

HTTP请求方法定义了发送请求的客户端想要执行的动作,而HTTP请求的首部则记录了与请求本身以及客户端有关的信息。请求的首部由任意多个用冒号分隔的纯文本键值对组成,最后以回车(CR)和换行(LF)结尾。

作为HTTP 1.1 RFC的一部分,RFC 7231对主要的一些HTTP请求字段(request field)进行了标准化。过去,非标准的HTTP请求通常以X-作为前缀,但标准并没有沿用这一惯例。

大多数HTTP请求首部都是可选的,宿主(Host)首部字段是HTTP 1.1唯一强制要求的首部。根据请求使用的方法不同,如果请求的报文中包含有可选的主体,那么请求的首部还需要带有内容长度(Content-Length)字段或者传输编码(Transfer-Encoding)字段。表1-1展示了一些常见的请求首部。表1-1 常见的HTTP请求首部首部字段作用描述客户端在HTTP响应中能够接收的内容类型。比如说,Accept客户端可以通过Accept: text/html这个首部,告知服务器自己希望在响应的主体中收到HTML类型的内容客户端要求服务器使用的字符集编码。比如说,客户Accept-端可以通过Accept-Charset: utf-8这个首部,告知服务Charset器自己希望响应的主体使用UTF-8字符集Authorization这个首部用于向服务器发送基本的身份验证证书客户端应该在这个首部中把服务器之前设置的所有cookie回传给服务器。比如说,如果服务器之前在浏览器上设置了3个cookie,那么Cookie首部字段将在一个Cookie字符串里面包含这3个cookie,并使用分号对这些cookie进行分隔。以下是一个Cookie首部示例:Cookie: my_first_cookie=hello; my_second_cookie=worldContent-请求主体的字节长度Length当请求包含主体的时候,这个首部用于记录主体内容的类型。在发送POST或PUT请求时,内容的类型默认Content-Type为x-www-form-urlen-coded,但是在上传文件时,内容的类型应该设置为multipart/form-data(上传文件这一操作可以通过将input标签的类型设置为file来实现)服务器的名字以及端口号。如果这个首部没有记录服Host务器的端口号,就表示服务器使用的是80端口Referrer发起请求的页面所在的地址User-Agent对发起请求的客户端进行描述1.6 HTTP响应

HTTP响应报文是对HTTP请求报文的回复。跟HTTP请求一样,HTTP响应也是由一系列文本行组成的,其中包括:● 一个状态行;● 零个或任意数量的响应首部;● 一个空行;● 一个可选的报文主体。

也许你已经发现了,HTTP响应的组织方式跟HTTP请求的组织方式是完全相同的。以下是一个典型的HTTP响应的样子(为了节省篇幅,我们省略了报文主体中的部分内容):200 OKDate: Sat, 22 Nov 2014 12:58:58 GMTServer: Apache/2 Last-Modified: Thu, 28 Aug 2014 21:01:33 GMTContent-Length: 33115Content-Type: text/html; charset=iso-8859-1 Hypertext Transfer Protocol -- HTTP/1.1...

HTTP响应的第一行为状态行,这个文本行包含了状态码(status code)和相应的原因短语(reason phrase),原因短语对状态码进行了简单的描述。除此之外,这个例子中的HTTP响应还包含了一个HTML格式的报文主体。1.6.1 响应状态码

正如之前所说,HTTP响应中的状态码表明了响应的类型。HTTP响应状态码共有5种类型,它们分别以不同的数字作为前缀,如表1-2所示。表1-2 HTTP响应状态码状态码类型作用描述情报状态码。服务器通过这些状态码来告知客户端,1XX自己已经接收到了客户端发送的请求,并且已经对请求进行了处理

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载