web 服务是定义在不同计算机系统之间的通信机制。如果没有 web 服务,定制的点对点通信将变得繁琐且特定于平台。网络需要理解和解释的东西有上百种。如果计算机系统与网络容易理解的协议相一致,这将是一个很大的帮助。
web 服务是一种软件系统,旨在通过网络支持可互操作的机器对机器交互,万维网联盟(W3C),https://www.w3.org/TR/ws-arch/ 。
现在,简单地说,web 服务是两个端点之间的一条通道,在这两个端点之间消息可以顺利传输。在这里,这种转移通常是一种方式。两个单独的可编程实体也可以通过各自的 API 相互通信。两个人通过语言交流。两个应用程序通过应用程序编程接口(API进行通信。
读者可能会疑惑;API 在当前数字世界中的重要性是什么?物联网(物联网的兴起使得 API 的使用量比以前更大。人们对 API 的认识与日俱增,世界各地每天都在开发和记录数百种 API。值得注意的主要业务是在API 中将期货视为一项服务(AAAS)。一个很好的例子是亚马逊网络服务(AWS)。这在云世界是一个巨大的成功。开发人员使用 AWS 提供的 RESTAPI 编写自己的应用程序
还有一些隐藏的用例来自于像 Ibibo 和 Expedia 这样的旅游网站,它们通过调用第三方网关和数据供应商的 API 来获取实时价格。如今,Web 服务经常收费。
本章涉及的主题包括:
有许多类型的 web 服务随着时间的推移而不断发展。突出的是:
其中,SOAP在 21 世纪初开始流行,当时 XML 是最流行的。XML 数据格式被各种分布式系统用来相互通信。SOAP 太复杂,无法实现。SOAP 的批评者指出 SOAP HTTP 请求是多么庞大。
SOAP 请求通常由以下三个基本组件组成:
为了执行 HTTP 请求和响应周期,我们必须在 SOAP 中附加大量额外的数据。示例 SOAP 请求如下所示:
POST /StockQuote HTTP/1.1
Host: www.stockquoteserver.com
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "Some-URI"
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:GetLastTradePrice xmlns:m="Some-URI">
<symbol>DIS</symbol>
</m:GetLastTradePrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
这是 W3C 标准(中 SOAP 的标准示例 https://www.w3.org/TR/2000/NOTE-SOAP-20000508/ )。如果我们仔细观察,它是 XML 格式的,带有指定信封和正文的特殊标记。由于 XML 在许多名称空间上运行,因此附加信息起作用
加利福尼亚大学的 Roy Fielding 创造了代表性的状态转移(TytT2)。与 SOAP 相比,它是一个非常简化和轻量级的 web 服务。性能、可扩展性、简单性、可移植性和可修改性是 REST 设计背后的主要原则
RESTAPI 允许不同的系统以非常简单的方式进行通信和发送/接收数据。每个 RESTAPI 调用都有一个 HTTP 谓词和 URL 之间的关系。应用程序中数据库中的资源可以映射到 REST 中的 API 端点。
当您在手机上使用移动应用程序时,您的手机可能会秘密与许多云服务通话,以检索、更新或删除您的数据。休息服务对我们的日常生活有着巨大的影响。
REST 是一种无状态、可缓存且简单的体系结构,它不是一种协议,而是一种模式。
与以前的版本相比,这些主要特性使 REST 变得简单和独特:
****深思熟虑的缓存对于 REST 服务的扩展至关重要。
REST 谓词指定对特定资源或资源集合执行的操作。当客户端发出请求时,它应在 HTTP 请求中发送以下信息:
正如我们前面提到的,REST 使用 URI 来解码要处理的资源。详情如下:
GET
POST
PUT
PATCH
DELETE
OPTIONS
如果你是一名软件开发人员,你大部分时间都要处理这六个问题。下表说明了操作、目标资源以及请求成功或失败时的情况:
| 休息动词 | 动作 | 成功 | 故障 |
| GET
| 从服务器获取一条记录或一组资源 | 200 | 404 |
| OPTIONS
| 获取所有可用的 REST 操作 | 200 | - |
| POST
| 创建一组新的资源或资源 | 201 | 404, 409 |
| PUT
| 更新或替换给定记录 | 200, 204 | 404 |
| PATCH
| 修改给定的记录 | 200, 204 | 404 |
| DELETE
| 删除给定的资源 | 200 | 404 |
上表成功和失败列中的数字为 HTTP 状态码。每当客户端启动 REST 操作时,由于 REST 是无状态的,客户端应该知道一种方法来确定操作是否成功。因此,HTTP 具有响应的状态代码。REST 为给定操作定义前面的状态代码类型。这意味着 RESTAPI 应该严格遵循前面的规则来实现客户端-服务器通信。
所有定义的 REST 服务都具有以下格式。它由主机和 API 端点组成。API 端点是服务器预定义的 URL 路径。每个 REST 请求都应该符合该路径。
一个简单的 RESTAPI URI:http://HostName/API endpoint/Query(optional)
让我们更详细地看一下所有的动词。RESTAPI 设计从定义操作和 API 端点开始。在实现 API 之前,设计文档应该列出给定资源的所有端点。在下一节中,我们将使用 PayPal 的 RESTAPI 作为用例仔细观察 RESTAPI 端点。
GET
方法从服务器获取给定的资源。为了指定资源,GET
使用几种类型的 URI 查询:
如果您不知道,您对 web 的所有浏览都是通过向服务器执行GET
请求来完成的。例如,如果您键入www.google.com,您实际上是在发出GET
请求以获取搜索页面。在这里,您的浏览器是客户端,而 Google 的 web 服务器是 web 服务的后端实现者。成功的GET
操作返回 200 状态码。
路径参数示例:
大家都知道贝宝。PayPal 与公司签订账单协议。如果您向 PayPal 注册支付系统,他们将为您提供一个 REST API,以满足您所有的计费需求。获取账单协议信息的样本GET
请求如下所示:/v1/payments/billing-agreements/agreement_id
。
这里,资源查询使用 path 参数。当服务器看到这一行时,它将其解释为我收到了一个 HTTP 请求,需要来自计费协议的协议 id。然后它搜索数据库,进入billing-agreements
表,找到与给定agreement_id
的协议。如果该资源存在,它将发送详细信息以复制回响应(200 OK)。或者,它发送一个响应,表示未找到资源(404)。
使用GET
,您还可以查询资源列表,而不是像前面的示例那样查询单个资源。PayPal 用于获取与协议相关的账单交易的 API 可以通过/v1/payments/billing-agreements/transactions
获取。此行获取该账单协议上发生的所有交易。在这两种情况下,案例数据都是以 JSON 响应的形式检索的。响应格式应事先设计,以便客户可以在协议中使用。
查询参数的示例如下:
GET
请求的查询参数将采用以下格式:**```go /v1/books/?category=fiction&publish_date=2017
* 前面的 URI 几乎没有查询参数。URI 正在从满足以下条件的图书资源请求图书:
* 它应该是一本小说
* 这本书应该在 2017 年出版
*获取 2017 年发布的所有小说*是客户端向服务器提出的问题
路径与查询参数何时使用?通常的经验法则是使用`Query`参数根据查询参数获取多个资源。如果客户端需要具有确切 URI 信息的单个资源,则可以使用`Path`参数指定该资源。例如,可以使用`Path`参数请求用户仪表板,并且可以使用`Query`参数对过滤数据进行建模。
在`GET`请求中,对单个资源使用`Path`参数,对多个资源使用`Query`参数。
# POST、PUT 和 PATCH
`POST`方法用于在服务器上创建资源。在上一本书的 API 中,此操作将创建具有给定详细信息的新书。成功的`POST`操作返回 201 状态码。`POST`请求可以更新多个资源:`/v1/books`。
`POST`请求的主体如下:
```go
{"name" : "Lord of the rings", "year": 1954, "author" : "J. R. R. Tolkien"}
这实际上在数据库中创建了一本新书。为该记录分配了一个 ID,以便在我们GET
资源时,创建 URL。所以POST
一开始只能做一次。事实上,指环王出版于 1955 年。因此,我们输入的发布日期不正确。为了更新资源,让我们使用PUT
请求。
PUT
方法与POST.
类似,用于替换已经存在的资源。主要区别在于PUT
是幂等的。一个POST
调用创建两个具有相同数据的实例。但是PUT
更新了一个已经存在的资源:
/v1/books/1256
主体是 JSON,如下所示:
{"name" : "Lord of the rings", "year": 1955, "author" : "J. R. R. Tolkien"}
1256
是这本书的 ID。它通过year:1955
更新前一本书。您是否注意到了PUT
的缺点?它实际上用新唱片替换了整个旧唱片。我们需要更改单个列。但是PUT
取代了整个记录。这很糟糕。为此,引入了PATCH
请求
PATCH
方法与PUT
类似,只是不会替换整个记录。顾名思义,PATCH
对正在修改的列进行了修补。让我们用一个名为ISBN
的新专栏来更新这本书1256
:
/v1/books/1256
JSON 主体如下所示:
{"isbn" : "0618640150"}
它告诉服务器,搜索 id 为 1256 的书。然后使用给定值添加/修改此列。
PUT
and PATCH
both return the 200 status for success and 404 for not found.
DELETE
API 方法用于从数据库中删除资源。与PUT
相似,但没有任何主体。它只需要一个要删除的资源 ID。一旦资源被删除,后续的GET
请求将返回 404 未找到状态
对该方法的响应是不可缓存(如果实现了缓存),因为DELETE
方法是幂等的。
**OPTIONS
API 方法是 API 开发中最被低估的方法。给定资源,此方法尝试了解服务器上定义的所有可能方法(GET
、POST
等)。这就像在餐馆里看菜单卡,然后点一道菜(如果你随意点了一道菜,服务员会告诉你没有)。在服务器上实现OPTIONS
方法是最佳实践。从客户端,确保首先调用了OPTIONS
,如果该方法可用,则继续该方法
此OPTIONS
方法最重要的应用是跨源资源共享(CORS。最初,浏览器安全性阻止客户端发出跨源请求。这意味着加载了 URLwww.foo.com的站点只能对该主机进行 API 调用。如果客户端代码需要从www.bar.com请求文件或数据,那么第二台服务器bar.com应该有识别foo.com的机制来获取其资源。
该过程解释了 CORS:
OPTIONS
方法。Access-Control-Allow-Origin: http://foo.com
的头信息。REST
方法的限制。如果bar.com在一个初始请求后想要向任何主机提供资源,它可以将访问控制设置为*(即任意)。
下图描述了一个接一个发生的过程:
有几个家庭的身份代码。每个族全局解释一个操作状态。这个家庭的每个成员都可能有一次更深入的会面。因此 restapi 应该严格地告诉客户端操作后到底发生了什么。有 60 多个状态代码可用。但对于其余部分,我们将重点关注几个代码族。
200 和 201 属于成功家族。它们表明手术是成功的。普通200(操作成功是成功的积垢操作:
POST
操作在服务器上成功创建资源时,返回201(成功创建)
* 204(无内容)在客户端需要状态但没有数据返回时发出
**# 3xx 系列(重定向)
这些状态代码用于传递重定向消息。最重要的是301和304:
* 当资源永久移动到新的 URL 端点时,发出301**。当旧 API 被弃用时,这一点至关重要。它在响应中返回状态为 301 的新端点。看到这一点,客户端应该使用新的 URL 来响应实现其目标。
这些是客户端需要解释和处理进一步操作的标准错误状态代码。这些与服务器无关。错误的请求格式或格式错误的 REST 方法可能导致这些错误。其中,API 开发者最常用的状态代码是400、401、403、404和405:
GET
和HEAD
为例外情况。这些是来自服务器的错误。客户端请求可能是完美的,但由于服务器代码中的错误,可能会出现这些错误。常用状态码为500、501、502、503、504:
有关状态代码的更多详细信息,请访问此链接:https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
您需要了解为什么单页应用程序(SPA)是今天的热门话题。这些 SPA 设计使开发人员以完全不同的方式编写代码,而不是以传统的方式构建 UI(请求网页)。有许多 MVC 框架,如 AngularJS、Angular2、React JS、Knockout JS、Aurelia 等,可以快速开发 web UI,但它们的本质都非常简单。所有 MVC 框架都帮助我们实现一种设计模式。该设计模式没有对网页的请求,只有 RESTAPI。
自 2010 年以来,现代 web 前端开发取得了很大进步。为了利用 AutoT0}模型视图控制器 ALE T1(MultT2 MVC OutT3)体系结构的特点,我们需要考虑前端是一个单独的实体,它只使用 REST API(最优选的是 REST JSON)与后端进行对话。
所有网站都要经过以下步骤:
但在水疗中心,水流是完全不同的:
这样,通信只以 RESTAPI 的形式发生。客户端负责逻辑地表示数据。这导致系统从面向响应的架构(ROA)转向面向服务的架构(SOA)。请看下图:
SPA 减少了带宽并提高了站点性能。
REST 服务在现代 web 中是微不足道的。SOA(稍后我们将更详细地讨论)为 REST 服务创建了一个活动空间,将 web 开发提升到一个新的水平。Go是来自 Google 之家的一种编程语言,用于解决他们面临的更大问题。它自第一次出现以来已经八年多了。随着开发人员社区的加入,它逐渐成熟,并在其中创建了大规模的系统。
围棋是网络的宠儿。它以一种简单的方式解决更大的问题。
可以选择 Python 或 JavaScript(节点)进行 RESTAPI 开发。Go 的主要优点在于它的速度和编译时错误检测。通过各种基准测试,Go 在计算性能方面被证明比动态编程语言更快。以下是公司应该在 Go 中编写下一个 API 的三个原因:
您可以查看无休止的在线辩论,以了解有关使用 Go 的 REST 服务的更多信息。在后面的章节中,我们将尝试构建设计和编写 REST 服务的基础。
这是一本建筑系列书。它假设你已经知道围棋的基本知识。如果没有,不用担心。您可以从 Go 官方网站快速入门并学习 https://golang.org/ 。Go 使用不同的方式开发项目。编写一个独立的、简单的程序不会给你带来太多麻烦。但是,在学习了基础知识之后,人们试图更进一步。因此,作为一名 Go 开发人员,您应该知道 Go 项目是如何布局的,以及保持代码整洁的最佳实践。
在继续之前,请确保已完成以下操作:
GOROOT
和GOPATH
环境变量有许多在线参考资料,您可以从中了解前面的详细信息。根据您的机器类型(Windows、Linux 或 macOS X),设置一个运行的 Go 编译器。关于GOPATH
的更多细节,请参见下一节。
GOPATH
只是您机器上当前指定的工作区。它是一个环境变量,告诉 Go 编译器源代码、二进制文件和包的放置位置。
来自 Python 背景的程序员可能知道 Virtualenv 工具,可以同时创建多个项目(使用不同的 Python 解释器版本)。但在给定的时间,一个人激活环境并开发他的项目。类似地,您的机器上可以有任意数量的 Go 项目。在开发过程中,将GOPATH
设置为您的一个项目。Go 编译器现在激活该项目。
通常的做法是在主目录下创建一个项目,并按如下方式设置GOPATH
环境变量:
>mkdir /home/naren/myproject
export GOPATH=/home/naren/myproject
现在,我们安装如下外部软件包:
go get -u -v github.com/gorilla/mux
Go 将名为mux
的项目复制到当前激活的项目myproject
中。
对于 Go-get,使用-u
标志安装外部包的更新依赖项,并使用-v
查看详细的安装细节。
一个典型的围棋项目具有以下结构,如围棋官方网站所述:
在进一步挖掘之前,让我们先了解该结构:
bin
:存储我们项目的二进制文件;可直接运行的可交付二进制文件pkg
:包含包对象;提供包方法的已编译程序src
:项目源代码、测试和用户包所在的位置在 Go 中,您导入到主程序中的所有包都具有相同的结构,github.com/user/project
。但是谁创建了所有这些目录呢?开发者应该这样做吗?不。开发人员有责任为其项目创建目录。表示他/她只创建目录src/github.com/user/hello
。
当开发人员运行以下命令时,如果目录 bin 和 package 以前不存在,则会创建它们。.bin
由我们的项目源代码的二进制组成,.pkg
由我们在 Go 程序中使用的所有内部和外部包组成:
go install github.com/user/project
根据我们迄今为止构建的概念,让我们编写第一个基本的 REST 服务。此服务从客户端获取数字范围(1-10)并返回其罗马字符串。非常原始,但比 Hello World 更好。
设计:
我们的 RESTAPI 应该从客户端获取一个整数,并返回罗马等价物。
API 设计文档的块可能如下所示:
| HTTP 动词 | 路径 | 动作 | 资源 |
| GET
| /roman_number/2
| 显示 | roman_number
|
执行情况:
现在我们将逐步实现前面的简单 API。
本项目的代码可在上找到 https://github.com/narenaryan/gorestful
如前所述,您应该首先设置GOPATH
。假设GOPATH
是/home/naren/go
。在下面的路径中创建一个名为romanserver
的目录。将narenaryan替换为您的 GitHub 用户名(这只是属于不同用户的代码的名称空间):
mkdir -p $GOPATH/src/github.com/narenaryan/romanserver
我们的项目已经准备好了。我们还没有配置任何数据库。创建一个名为main.go
的空文件:
touch $GOPATH/src/github.com/narenaryan/romanserver/main.go
API 服务器的主要逻辑进入这个文件。现在,我们可以创建一个数据文件,作为主程序的数据服务。再创建一个用于打包罗马数字数据的目录:
mkdir $GOPATH/src/github.com/narenaryan/romanNumerals
现在,在romanNumerals
目录中创建一个名为data.go
的空文件。到目前为止,src
目录结构如下:
;
现在让我们开始向文件中添加代码。为罗马数字创建数据:
// data.go
package romanNumerals
var Numerals = map[int]string{
10: "X",
9: "IX",
8: "VIII",
7: "VII",
6: "VI",
5: "V",
4: "IV",
3: "III",
2: "II",
1: "I",
}
我们正在创建一个名为数字的地图。此映射包含将给定整数转换为罗马等效整数的信息。我们将把这个变量导入我们的主程序,以满足客户端的请求
打开main.go
并添加以下代码:
// main.go
package main
import (
"fmt"
"github.com/narenaryan/romanNumerals"
"html"
"net/http"
"strconv"
"strings"
"time"
)
func main() {
// http package has methods for dealing with requests
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
urlPathElements := strings.Split(r.URL.Path, "/")
// If request is GET with correct syntax
if urlPathElements[1] == "roman_number" {
number, _ := strconv.Atoi(strings.TrimSpace(urlPathElements[2]))
if number == 0 || number > 10 {
// If resource is not in the list, send Not Found status
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("404 - Not Found"))
} else {
fmt.Fprintf(w, "%q", html.EscapeString(romanNumerals.Numerals[number]))
}
} else {
// For all other requests, tell that Client sent a bad request
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("400 - Bad request"))
}
})
// Create a server and run it on 8000 port
s := &http.Server{
Addr: ":8000",
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}
始终使用 Go fmt 工具格式化 Go 代码。
使用示例:go fmt github.com/narenaryan/romanserver
现在,使用 Go 命令install
安装此项目:
go install github.com/narenaryan/romanserver
此步骤有两个功能:
romanNumerals
并将副本放在$GOPATH/pkg
目录中$GOPATH/bin
中放置二进制文件我们可以按如下方式运行前面的 API 服务器:
$GOPATH/bin/romanserver
服务器已启动并在http://localhost:8000
上运行。现在,我们可以使用类似于Browser
或CURL
命令的客户端向 API 发出GET
请求。让我们使用适当的 APIGET
请求触发一个CURL
命令。
请求一如下:
curl -X GET "http://localhost:8000/roman_number/5" # Valid request
答复如下:
HTTP/1.1 200 OK
Date: Sun, 07 May 2017 11:24:32 GMT
Content-Length: 3
Content-Type: text/plain; charset=utf-8
"V"
让我们尝试一些格式不正确的请求。
请求二如下:
curl -X GET "http://localhost:8000/roman_number/12" # Resource out of range
答复如下:
HTTP/1.1 404 Not Found
Date: Sun, 07 May 2017 11:22:38 GMT
Content-Length: 15
Content-Type: text/plain; charset=utf-8
404 - Not Found
请求三如下:
curl -X GET "http://localhost:8000/random_resource/3" # Invalid resource
答复如下:
"HTTP/1.1 400 Bad request
Date: Sun, 07 May 2017 11:22:38 GMT
Content-Length: 15
Content-Type: text/plain; charset=utf-8
400 - Bad request
我们的小罗马数字 API 正在做正确的事情。正在返回正确的状态代码。这是所有 API 开发人员都应该牢记的一点。应告知客户出现问题的原因。
我们只是一次性更新了空文件,并开始运行服务器。现在让我解释文件main.go
的每一部分:
github.com/narenaryan/romanNumerals
是我们之前创建的数据服务。net/http
是我们用来通过HandleFunc
功能处理 HTTP 请求的核心包。该函数的参数是http.Request
和http.ResponseWriter
。这两个函数处理 HTTP 请求的请求和响应。r.URL.Path
是 HTTP 请求的 URL 路径。对于卷曲请求一,它是/roman_number/5
。我们正在拆分此路径,并使用第二个参数作为资源,第三个参数作为值来获取罗马数字。Split
函数位于名为strings
的核心包中。Atoi
函数将字母数字字符串转换为整数。对于要使用的数字映射,我们需要将整数字符串转换为整数。Atoi
函数来自一个名为strconv
的核心包。http.StatusXXX
设置响应头的状态码。响应对象上提供了WriteHeader
和Write
函数,分别用于写入标题和正文。&http
创建了一个 HTTP 服务器,同时初始化了一些参数,如地址、端口、超时等。time
包用于定义程序中的秒数。它表示,在 10 秒不活动之后,自动将 408 请求超时返回给客户端。EscapeString
将特殊字符转义为有效的 HTML 字符。例如,弗兰&弗雷迪的成为Fran & Freddie's"
。ListenAndServe
功能启动服务器。它会让您的 web 服务器一直运行,直到您杀死它。应该为他们的 API 编写单元测试。在接下来的章节中,我们将看到如何端到端测试 API
Gulp 是创建工作流的好工具。工作流是一个循序渐进的过程。它只是一个简化应用程序的任务。您需要在计算机上安装 NPM 和节点。我们使用 Gulp 监视文件,然后更新二进制文件并重新启动 API 服务器。听起来很酷,对吧?
supervisor 是一个应用程序,在应用程序被终止时重新加载服务器。将为您的服务器分配一个进程 ID。要正确地重新启动应用程序,我们需要杀死现有实例并重新启动应用程序。我们可以用围棋写一个这样的程序。但是为了不重新发明轮子,我们正在使用一个叫做 supervisord 的流行程序。
有时,由于操作系统重新启动或崩溃,web 应用程序可能会停止。每当您的 web 服务器被杀死时,主管的工作就是让它恢复活力。即使重新启动系统也无法使 web 服务器离开客户。因此,严格使用 supervisord 进行应用程序监控。
我们可以通过apt-get
命令在 Ubuntu 16.04 上轻松安装 supervisord:
sudo apt-get install -y supervisor
这将安装两个工具,supervisor
和supervisorctl
。supervisorctl
用于控制监控命令,添加任务、重启任务等。
在 macOS X 上,我们可以使用brew
命令安装supervisor
:
brew install supervisor
现在,在以下位置创建一个配置文件:
/etc/supervisor/conf.d/goproject.conf
您可以添加任意数量的配置文件,supervisord 将其视为单独的进程来运行。将以下内容添加到前面的文件:
[supervisord]
logfile = /tmp/supervisord.log
[program:myserver]
command=$GOPATH/bin/romanserver
autostart=true
autorestart=true
redirect_stderr=true
默认情况下,我们在/etc/supervisor/
有一个名为.supervisord.conf
的文件。请看它以获取更多参考。在 macOS X 中,相同的文件将位于/usr/local/etc/supervisord.ini
。
转到前面的配置:
[supervisord]
部分告诉 supervisord 日志文件的位置[program:myserver]
是遍历给定目录并执行给定命令的任务块现在我们可以要求我们的supervisorctl
重新读取配置并重新启动任务(流程)。对此,只需说:
supervisorctl reread
supervisorctl update
然后,用命令启动supervisorctl
:
supervisorctl
您将看到如下内容:
supervisorctl
is a great tool for controlling supervisor programs.
由于我们在 supervisor 配置文件中将 romanserver 命名为myserver
,因此我们可以从supervisorctl
启动、停止和重新启动该程序。
在上一节中,我们对 Gulp 做了一点介绍,我们将编写一个 gulpfile,告诉计算机执行一些任务。
我使用npm
安装气枪和气枪外壳
**```go npm install gulp gulp-shell
之后,在项目的根目录中创建一个`gulpfile.js`。这里是`github.com/src/narenaryan/romanserver`。现在将此内容添加到`gulpfile.js`。首先,每当文件发生更改时,都会执行 InstallBinary 任务。然后,将重新启动监控程序。监视任务查找任何文件更改并执行前面的任务。我们还对任务进行排序,以便它们一个接一个地同步发生。所有这些任务都是吞咽任务,可以通过`gulp.task`功能定义。它接受两个任务名为 task 的参数。`sell.task`允许 Gulp 执行系统命令:
```go
var gulp = require("gulp");
var shell = require('gulp-shell');
// This compiles new binary with source change
gulp.task("install-binary", shell.task([
'go install github.com/narenaryan/romanserver'
]));
// Second argument tells install-binary is a deapendency for restart-supervisor
gulp.task("restart-supervisor", ["install-binary"], shell.task([
'supervisorctl restart myserver'
]))
gulp.task('watch', function() {
// Watch the source code for all changes
gulp.watch("*", ['install-binary', 'restart-supervisor']);
});
gulp.task('default', ['watch']);
现在,如果您在source
目录中运行gulp
命令,它将开始监视您的源代码更改:
gulp
现在,如果我们修改代码,那么代码将被编译、安装,服务器将在闪存中重新启动:
在 gulpfile 中,我们执行以下说明:
shell.task
为执行函数的任务。shell.task
可以执行命令行指令。将 shell 命令保存在该函数中。对于这类用例来说,Gulp 是一个很好的工具。因此,请在查阅 Gulp 的官方文件 http://gulpjs.com/ 。
在本章中,我们介绍了 RESTAPI。我们看到 REST 不是一个协议,而是一个架构模式。HTTP 是我们可以实现 REST 服务的实际协议。我们深入了解了 RESTAPI 的基本原理,以明确它们实际上是什么。然后我们探讨了 web 服务的类型。在 REST 之前,我们有一种称为 SOAP 的东西,它使用 XML 作为数据格式。REST 使用 JSON 作为主要格式。REST 有动词和状态代码。我们看到了给定的状态代码所指的内容。我们构建了一个简单的服务,为给定的数字提供罗马数字。在这个过程中,我们还看到了如何打包 Go 项目。我们理解了 GOPATH 环境变量。它是一个在 Go 中定义变量的工作区。所有包和项目都位于该路径中。然后,我们看到了如何在 supervisord 和 Gulp 的帮助下动态地重新加载开发项目。这些是节点工具,但可以帮助我们保持 Go 项目的启动和运行。
在下一章中,我们将深入研究 URL 路由。从内置路由器开始,我们探索 Gorilla Mux,这是一个强大的 URL 路由库。**