通过hello World Web服务器宣告你的存在
标准库存中的net/http包提供了多种创建HTTP服务器的方法,它还提供了一个基本路由器。
使用Go语言编写的基础HTTP服务器,程序清单如下:
package main
import (
"net/http"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World\n"))
}
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":8000", nil)
}
运行结果,命令行内容一直没出来,在“http://localhost:8000/”网页上出现一句话:“Hello World”。
使用方法HandleFunc创建路由。这个方法接受一个模式和一个函数,其中前者描述了路径,而后者指定如何对发送到该路径的请求做出响应。
为响应客户端,使用方法ListenAndServe来启动一个服务器,这个服务器监听localhost和端口8000.
查看请求和响应
curl是一款用于发起HTTP请求的命令行工具。需要安装curl.
输入命令行如下:
curl --version
代码如下:
curl 7.77.0 (x86_64-apple-darwin21.0) libcurl/7.77.0 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.42.0
Release-Date: 2021-05-26
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL UnixSockets
使用curl发出请求
安装curl后,就可在开发和调试Web服务器时使用它。不使用Web浏览器,而使用curl来向Web服务器发送各种请求以及查看响应。
打开终端并运行这个服务器,代码如下:
go run main.go
再打开另一个终端,执行下面的命令,其中的选项-is指定打印报头。如下:
curl -is http://localhost:8000
运行结果如下:
HTTP/1.1 200 OK
Date: Mon, 31 Jan 2022 14:10:10 GMT
Content-Length: 12
Content-Type: text/plain; charset=utf-8
Hello World
这个响应使用的协议为HTTP 1.1,状态码为200 。
报头Date详细地描述了响应的发送时间。
报头Content-Length详细地指出了响应的长度,这里是12字节。
报头Content-Type指出了内容的类型以及使用的编码。在这里,响应的内容类型为text/plain,是使用utf-8进行编码的。
最后输出的是响应体,这里是Hello World。
详谈路由:
HandleFunc用于注册对URL地址映射进行响应的函数。简单地说着,HandleFunc创建一个路由表,让HTTP服务器能够正确地做出响应。
http.HandleFunc("/",helloworld)
http.HandleFunc("/users/",usersHandler)
http.HandleFunc("/projects/",projectsHandler)
每当用户向/发出请求时,都将调用函数helloWorld,每当用户向/users/发出请求时,都将调用函数sersHandler,依此类推。
使用处理程序函数
处理404错误
默认路由器的行为是将所有没有指定处理程序的请求都定向到/。回到第一个示例,如果用户请求的页面不存在,将调用给/指定的处理程序,从而返回响应Hello World和状态码200 。
代码如下:
package main
import (
"net/http"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.Write([]byte("Hello World\n"))
}
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":8000", nil)
}
使用go run命令行时,输入另外一个命令行如下:
curl -is http://localhost:8000/asdfa
运行结果如下:
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Fri, 04 Feb 2022 07:25:38 GMT
Content-Length: 19
404 page not found
设置报头
处理程序函数可使用ResponseWriter来添加报头。如下所示:
w.Header().Set("Content-Type", "application/json; charset=utf-8")
在响应中添加报头,代码如下:
package main
import (
"net/http"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write([]byte(`{"hello": "world"}`))
}
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":8000", nil)
}
使用go run命令行时,输入另外一个命令行如下:
curl -is http://localhost:8000/
运行结果如下:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Fri, 04 Feb 2022 07:33:24 GMT
Content-Length: 18
{"hello": "world"}
响应以不同类型的内容
以不同类型的内容进行响应,代码如下:
package main
import (
"net/http"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
switch r.Header.Get("Accept") {
case "application/json":
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write([]byte(`{"message": "Hello World"}`))
case "application/xml":
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
w.Write([]byte(`Hello World `))
default:
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write([]byte("Hello World\n"))
}
}
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":8000", nil)
}
使用go run命令行时,输入另外一个命令行如下:
curl -si -H 'Accept: application/json' http://localhost:8000
运行结果如下:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Fri, 04 Feb 2022 08:31:23 GMT
Content-Length: 26
{"message": "Hello World"}
使用go run命令行时,输入另外一个命令行如下:
curl -si -H 'Accept: application/xml' http://localhost:8000
命令行的运行结果如下:
HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
Date: Fri, 04 Feb 2022 08:30:36 GMT
Content-Length: 68
Hello World
响应不同类型的请求
代码如下:
package main
import (
"net/http"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
switch r.Method {
case "GET":
w.Write([]byte("Received a GET request\n"))
case "POST":
w.Write([]byte("Received a POST request\n"))
default:
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte(http.StatusText(http.StatusNotImplemented)) + "\n")
}
}
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":8000", nil)
}
代码错误如下:
# command-line-arguments
./main.go:19:62: invalid operation: ([]byte)(http.StatusText(http.StatusNotImplemented)) + "\n" (mismatched types []byte and untyped string)
只能删除"\n",这个,才能运行成功。
使用go run命令行时,输入另外一个命令行如下:
curl -si -X GET http://localhost:8000
命令行的运行结果如下:
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2022 09:01:49 GMT
Content-Length: 23
Content-Type: text/plain; charset=utf-8
Received a GET request
使用go run命令行时,输入另外一个命令行如下:
curl -si -X POST http://localhost:8000
命令行的运行结果如下:
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2022 09:02:16 GMT
Content-Length: 24
Content-Type: text/plain; charset=utf-8
Received a POST request
获取GET和POST请求中的数据
处理不同请求中的数据,代码如下:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
switch r.Method {
case "GET":
for k, v := range r.URL.Query() {
fmt.Printf("%s: %s\n", k, v)
}
w.Write([]byte("Received a GET request\n"))
case "POST":
reqBody, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", reqBody)
w.Write([]byte("Received a POST request\n"))
default:
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte(http.StatusText(http.StatusNotImplemented)))
}
}
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":8000", nil)
}
使用go run命令行时,输入另外一个命令行如下:
curl -si "http://localhost:8000/?foo=1&bar=2"
命令行的运行结果如下:使用curl向这个Web服务器发出包含一些查询参数的GET请求。
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2022 08:55:50 GMT
Content-Length: 23
Content-Type: text/plain; charset=utf-8
Received a GET request
代码的运行结果如下:
bar: [2]
foo: [1]
使用go run命令行时,输入另外一个命令行如下:
curl -si POST -d "some data to send" http://localhost:8000/
命令行的运行结果如下:使用curl向这个Web服务器发出POST请求。
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2022 08:59:10 GMT
Content-Length: 24
Content-Type: text/plain; charset=utf-8
Received a POST request
代码的运行结果如下:
some data to send