1,071
社区成员




net/http
包以及如何将其用于生产就绪的 Web 应用程序进行了广泛的讨论。我们主要关注路由方面以及该
http.ServeMux
类型的其他怪癖和特性。
本文将ServeMux
通过演示如何使用默认路由器实现中间件功能并介绍在使用 Go 开发 Web 服务时肯定会派上用场的其他标准库包来结束讨论。
设置需要为许多或所有 HTTP 请求运行的共享功能的做法称为中间件。一些操作,如身份验证、日志记录和 cookie 验证,通常作为中间件功能实现,它们在常规路由处理程序之前或之后独立地处理请求。
要在 Go 中实现中间件,你需要确保你有一个满足http.Handler接口的类型。通常,这意味着您需要将带有签名的方法附加
ServeHTTP(http.ResponseWriter, *http.Request)
到类型。使用此方法时,任何类型都将满足该http.Handler
接口。
这是一个简单的例子:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-string-color)">"net/http"</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-text-color)">helloHandler</span> <span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">h</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">ServeHTTP</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Write</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello "</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">h</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">helloJohn</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-error-color)">:</span> <span style="color:var(--syntax-string-color)">"John"</span><span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">helloJohn</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
发送到/john
路由的任何请求都将直接传递给该
helloHandler.ServeHTTP
方法。您可以通过启动服务器并前往http://localhost:8080/john 来观察实际情况。
ServeHTTP
每次要实现一个方法时都必须将方法添加到自定义类型http.Handler
会非常乏味,因此该net/http
包提供了该http.HandlerFunc
类型,它允许将普通函数用作 HTTP 处理程序。
您需要做的就是确保您的函数具有以下签名
func(http.ResponseWriter, *http.Request)
:然后,将其转换为
http.HandlerFunc
类型。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-string-color)">"net/http"</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">helloJohnHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Write</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello John"</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">helloJohnHandler</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
您甚至可以将上面函数mux.Handle
中的行替换为,并将该函数直接传递给它。我们在上一篇文章中专门使用了这种模式。main
mux.HandleFunc
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandleFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">helloJohnHandler</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
此时,名称被硬编码到字符串中,这与之前我们能够在main
调用处理程序之前在函数中设置名称不同。要消除此限制,我们可以将处理程序逻辑放入闭包中,如下所示:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-string-color)">"net/http"</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Write</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello "</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"John"</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
函数helloHandler
本身不满足http.Handler
接口,但它创建并返回一个满足接口的匿名函数。此函数关闭name
参数,这意味着它可以在调用时访问它。此时,该helloHandler
函数可以根据需要重复用于许多不同的名称。
那么,这一切与中间件有什么关系呢?好吧,创建中间件函数的方法与我们在上面看到的相同。我们可以将链中的下一个处理程序作为参数传递,而不是将字符串传递给闭包(如示例中所示)。
这是完整的模式:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">middleware</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">next</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Middleware logic goes here...</span>
<span style="color:var(--syntax-text-color)">next</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ServeHTTP</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
上面的函数middleware
接受一个处理程序并返回一个处理程序。请注意我们如何能够通过将匿名函数http.Handler
转换为类型来满足接口的要求http.HandlerFunc
。在匿名函数的末尾,next
通过调用
ServeHTTP()
方法将控制权转移到处理程序。如果您需要在处理程序之间传递值,例如经过身份验证的用户的 ID,您可以使用http.Request.Context()
Go 1.7 中引入的方法。
让我们编写一个简单演示此模式的中间件函数。requestTime
此函数添加一个调用到请求对象的属性,随后用于helloHandler
显示请求的时间戳。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
<span style="color:var(--syntax-string-color)">"context"</span>
<span style="color:var(--syntax-string-color)">"net/http"</span>
<span style="color:var(--syntax-string-color)">"time"</span>
<span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">requestTime</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">next</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">ctx</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Context</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">ctx</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">context</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">WithValue</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">ctx</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"requestTime"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Now</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Format</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">RFC3339</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">WithContext</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">ctx</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">next</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ServeHTTP</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">responseText</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-string-color)">"<h1>Hello "</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-string-color)">"</h1>"</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">requestTime</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Context</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Value</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"requestTime"</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-text-color)">requestTime</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">ok</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">requestTime</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-text-color)">ok</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">responseText</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">responseText</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-literal-color)">\n</span><span style="color:var(--syntax-string-color)"><small>Generated at: "</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">str</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-string-color)">"</small>"</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Write</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">responseText</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">requestTime</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"John"</span><span style="color:var(--syntax-text-color)">)))</span>
<span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
由于我们的中间件函数接受并返回一个http.Handler
类型,因此可以
创建一个无限的中间件函数链,这些中间件函数相互嵌套
。
例如,
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">middleware1</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">middleware2</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">appHandler</span><span style="color:var(--syntax-text-color)">)))</span>
</code></span></span>
您可以使用像Alice这样的库将
上述结构转换为更具可读性的形式,例如:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">alice</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">New</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">middleware1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">middleware2</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Then</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">appHandler</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>
尽管模板的使用随着单页应用程序的出现而减少,但它仍然是完整 Web 开发解决方案的一个重要方面。
Go 为您的所有模板需求提供了两个包:text/template
和html/template
. 两者有相同的接口,但后者会在幕后做一些编码以防止代码注入攻击。
虽然 Go 模板不是最有表现力的,但它们可以很好地完成工作,并且可以用于生产应用程序。事实上,流行的静态站点生成器 Hugo 的模板系统就是基于它。
让我们快速了解一下该html/template
包如何用于发送 HTML 输出作为对 Web 请求的响应。
index.html
在你的文件所在的目录下创建一个文件main.go
,并在该文件中添加以下代码:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-error-color)"><ul></span>
{{ range .TodoItems }}
<span style="color:var(--syntax-error-color)"><li></span>{{ . }}<span style="color:var(--syntax-error-color)"></li></span>
{{ end }}
<span style="color:var(--syntax-error-color)"></ul></span>
</code></span></span>
接下来,将以下代码添加到您的main.go
文件中:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
<span style="color:var(--syntax-string-color)">"html/template"</span>
<span style="color:var(--syntax-string-color)">"log"</span>
<span style="color:var(--syntax-string-color)">"os"</span>
<span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">t</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">template</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ParseFiles</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"index.html"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">todos</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">[]</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">"Watch TV"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Do homework"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Play games"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Read"</span><span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">t</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Execute</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Stdout</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">todos</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
如果你用go run main.go
. 您应该看到以下输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-error-color)"><ul></span>
<span style="color:var(--syntax-error-color)"><li></span>Watch TV<span style="color:var(--syntax-error-color)"></li></span>
<span style="color:var(--syntax-error-color)"><li></span>Do homework<span style="color:var(--syntax-error-color)"></li></span>
<span style="color:var(--syntax-error-color)"><li></span>Play games<span style="color:var(--syntax-error-color)"></li></span>
<span style="color:var(--syntax-error-color)"><li></span>Read<span style="color:var(--syntax-error-color)"></li></span>
<span style="color:var(--syntax-error-color)"></ul></span>
</code></span></span>
恭喜!您刚刚创建了第一个 Go 模板。以下是我们在模板文件中使用的语法的简短说明:
{{
和}}
)来分隔模板中的数据评估和控制结构(称为操作)。range
是我们如何能够迭代数据结构,例如切片。.
表示当前上下文。在range
动作中,当前上下文是 的切片todos
。在块内部,{{ . }}
指的是切片中的每个元素。在main.go
文件中,该template.ParseFiles
方法用于从一个或多个文件创建新模板。该模板随后使用该template.Execute
方法执行;它需要一个io.Writer
和数据,这些数据将应用于模板。
在上面的例子中,模板被执行到标准输出,但我们可以将它执行到任何目的地,只要它满足接口io.Writer
。例如,如果您想要将输出作为 Web 请求的一部分返回,您需要做的就是将模板执行到界面ResponseWriter
,如下所示。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
<span style="color:var(--syntax-string-color)">"html/template"</span>
<span style="color:var(--syntax-string-color)">"log"</span>
<span style="color:var(--syntax-string-color)">"net/http"</span>
<span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">t</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">template</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ParseFiles</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"index.html"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">todos</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">[]</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">"Watch TV"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Do homework"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Play games"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Read"</span><span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandleFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/todos"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Header</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Set</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Content-Type"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"text/html"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">t</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Execute</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">todos</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Error</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Error</span><span style="color:var(--syntax-text-color)">(),</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">StatusInternalServerError</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-declaration-color)">nil</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
本节只是为了快速介绍 Go 的模板包。
如果您不喜欢 Go 的模板制作方式,可以使用替代方案,例如Plush 库。
如果您需要使用 JSON 对象,您会很高兴听到 Go 的标准库包含通过包解析和编码 JSON 所需的一切encoding/json
。
在 Go 中编码或解码 JSON 对象时,使用以下类型:
bool
对于 JSON 布尔值,float64
对于 JSON 数字,string
对于 JSON 字符串,nil
对于 JSON 空值,map[string]interface{}
对于 JSON 对象,以及[]interface{}
对于 JSON 数组。要将数据结构编码为 JSON,json.Marshal
可使用该函数。这是一个例子:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
<span style="color:var(--syntax-string-color)">"encoding/json"</span>
<span style="color:var(--syntax-string-color)">"fmt"</span>
<span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-text-color)">Person</span> <span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">FirstName</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">LastName</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">Age</span> <span style="color:var(--syntax-declaration-color)">int</span>
<span style="color:var(--syntax-text-color)">email</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">p</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">Person</span><span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">FirstName</span><span style="color:var(--syntax-error-color)">:</span> <span style="color:var(--syntax-string-color)">"Abraham"</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">LastName</span><span style="color:var(--syntax-error-color)">:</span> <span style="color:var(--syntax-string-color)">"Freeman"</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">Age</span><span style="color:var(--syntax-error-color)">:</span> <span style="color:var(--syntax-literal-color)">100</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">email</span><span style="color:var(--syntax-error-color)">:</span> <span style="color:var(--syntax-string-color)">"abraham.freeman@hey.com"</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Marshal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">p</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">return</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
在上面的程序中,我们有一个Person
包含四个不同字段的结构。在该main
函数中,创建了一个实例Person
,并初始化了所有字段。json.Marshal
然后使用该方法将p
结构转换为 JSON。此方法返回字节片段或错误,我们必须在访问 JSON 数据之前处理这些错误。
要在 Go 中将字节切片转换为字符串,我们需要执行类型转换,如上所示。运行该程序将产生以下
输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>{"FirstName":"Abraham","LastName":"Freeman","Age":100}
</code></span></span>
如您所见,我们得到了一个有效的 JSON 对象,可以以我们想要的任何方式使用。请注意,该email
字段被排除在结果之外。这是因为它不是Person
由于以小写字母开头而从对象中导出的。
默认情况下,Go 在结构中使用相同的属性名称作为结果 JSON 对象中的字段名称。然而,这可以通过使用 struct 字段标签来改变。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-text-color)">Person</span> <span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">FirstName</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-string-color)">`json:"first_name"`</span>
<span style="color:var(--syntax-text-color)">LastName</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-string-color)">`json:"last_name"`</span>
<span style="color:var(--syntax-text-color)">Age</span> <span style="color:var(--syntax-declaration-color)">int</span> <span style="color:var(--syntax-string-color)">`json:"age"`</span>
<span style="color:var(--syntax-text-color)">email</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-string-color)">`json:"email"`</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
上面的struct 字段标签指定JSON 编码器应该将FirstName
struct 中的属性映射到first_name
JSON 对象中的字段等等。上一个示例中的此更改会产生以下输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>{"first_name":"Abraham","last_name":"Freeman","age":100}
</code></span></span>
该json.Unmarshal
函数用于将 JSON 对象解码为 Go 结构。它具有以下签名:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">Unmarshal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">data</span> <span style="color:var(--syntax-text-color)">[]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">v</span> <span style="color:var(--syntax-declaration-color)">interface</span><span style="color:var(--syntax-text-color)">{})</span> <span style="color:var(--syntax-declaration-color)">error</span>
</code></span></span>
它接受 JSON 数据的字节切片和存储解码数据的位置。如果解码成功,返回的错误将是nil
。
假设我们有以下 JSON 对象,
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">json</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-string-color)">"{"</span><span style="color:var(--syntax-text-color)">first_name</span><span style="color:var(--syntax-string-color)">":"</span><span style="color:var(--syntax-text-color)">John</span><span style="color:var(--syntax-string-color)">","</span><span style="color:var(--syntax-text-color)">last_name</span><span style="color:var(--syntax-string-color)">":"</span><span style="color:var(--syntax-text-color)">Smith</span><span style="color:var(--syntax-string-color)">","</span><span style="color:var(--syntax-text-color)">age</span><span style="color:var(--syntax-string-color)">":35, "</span><span style="color:var(--syntax-text-color)">place_of_birth</span><span style="color:var(--syntax-string-color)">": "</span><span style="color:var(--syntax-text-color)">London</span><span style="color:var(--syntax-string-color)">", gender:"</span><span style="color:var(--syntax-text-color)">male</span><span style="color:var(--syntax-string-color)">"}"</span>
</code></span></span>
我们可以将其解码为结构的一个实例Person
,如下所示:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">b</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-string-color)">`{"first_name":"John","last_name":"Smith","age":35, "place_of_birth": "London", "gender":"male", "email": "john.smith@hmail.com"}`</span>
<span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-text-color)">p</span> <span style="color:var(--syntax-text-color)">Person</span>
<span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Unmarshal</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-text-color)">),</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">p</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">return</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Printf</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"%+v</span><span style="color:var(--syntax-literal-color)">\n</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">p</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
你会得到以下输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>{FirstName:John LastName:Smith Age:35 email:}
</code></span></span>
Unmarshal
仅解码在目标类型中找到的字段。在这种情况下,place_of_birth
和gender
被忽略,因为它们不映射到Person
. 可以利用此行为从大型 JSON 对象中仅选择几个特定字段。和以前一样,目标结构中未导出的字段不受影响,即使它们在 JSON 对象中有相应的字段也是如此。这就是为什么email
即使它存在于 JSON 对象中,输出中仍然是一个空字符串。
该database/sql
包提供了一个围绕 SQL(或类似 SQL)数据库的通用接口。它必须与数据库驱动程序结合使用,例如此处列出的驱动程序。导入数据库驱动时,需要在其前面加上下划线_
作为初始化
。
例如,下面是如何使用MySQL 驱动程序包database/sql
:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
<span style="color:var(--syntax-string-color)">"database/sql"</span>
<span style="color:var(--syntax-text-color)">_</span> <span style="color:var(--syntax-string-color)">"github.com/go-sql-driver/mysql"</span>
<span style="color:var(--syntax-text-color)">)</span>
</code></span></span>
在引擎盖下,驱动程序将自己注册为对包可用database/sql
,但它不会直接在我们的代码中使用。这有助于我们减少对特定驱动程序的依赖,以便可以轻松地将其换成另一个驱动程序。
要访问数据库,您需要创建一个sql.DB
对象,如下所示:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">sql</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Open</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"mysql"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"user:password@tcp(127.0.0.1:3306)/hello"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
该sql.Open
方法准备数据库抽象供以后使用。它不建立与数据库的连接或验证连接参数。如果要确保数据库立即可用和可访问,请使用以下db.Ping()
方法:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Ping</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
要关闭数据库连接,您可以使用db.Close()
. 通常,您希望defer
关闭数据库直到打开数据库连接的函数结束,通常是函数main
:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">sql</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Open</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"mysql"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"user:password@tcp(127.0.0.1:3306)/hello"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">defer</span> <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Close</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
该sql.DB
对象被设计为长期存在的,因此您不应频繁打开和关闭它。如果这样做,您可能会遇到问题,例如连接重用和共享不佳、可用网络资源耗尽或偶发故障。最好传递该sql.DB
方法或使其全局可用,并且仅在程序完成访问该数据存储时才关闭它。
查询表可以分三步完成。首先,打电话db.Query()
。然后,遍历行。最后,使用rows.Scan()
将每一行提取到变量中。这是一个例子:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-text-color)">(</span>
<span style="color:var(--syntax-text-color)">id</span> <span style="color:var(--syntax-declaration-color)">int</span>
<span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Query</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"select id, name from users where id = ?"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">defer</span> <span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Close</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Next</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Scan</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Err</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
如果查询返回单行,您可以使用该db.QueryRow
方法代替db.Query
并避免前面代码片段中的一些冗长的样板代码:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-text-color)">(</span>
<span style="color:var(--syntax-text-color)">id</span> <span style="color:var(--syntax-declaration-color)">int</span>
<span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">QueryRow</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"select id, name from users where id = ?"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Scan</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>
Go 还对 NoSQL 数据库有很好的支持,例如 Redis、MongoDB、Cassandra 等,但它没有提供与它们一起工作的标准接口。您必须完全依赖特定数据库的驱动程序包。下面列出了一些示例。
在本文中,我们讨论了
使用 Go 构建 Web 应用程序的一些重要方面。您现在应该能够理解为什么许多 Go 程序员对标准库发誓了。它非常全面,提供了生产就绪服务所需的大部分工具。
如果您喜欢这篇文章,请点赞、评论和分享。