[译]Go HTTTP Response代码片段

目录 [−]

  1. 只发送header
  2. 返回普通文本
  3. 返回JSON数据
  4. 返回XML数据
  5. 文件服务
  6. 使用HTML模版
  7. 使用HTML模板生成字符串
  8. 使用嵌套的模版

原文: HTTP Response Snippets for Go by Alex Edwards.

受 Rails layouts and rendering启发, 我觉得写一个关于Go HTTP Response的代码片段集合是一个不错的主意, 它可以用来说明Go web应用程序中通用的HTTP Response的使用。

只发送header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/", foo)
http.ListenAndServe(":3000", nil)
}
func foo(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Server", "A Go Web Server")
w.WriteHeader(200)
}

测试:

1
2
3
4
5
$ curl -i localhost:3000
HTTP/1.1 200 OK
Server: A Go Web Server
Content-Type: text/plain; charset=utf-8
Content-Length: 0

返回普通文本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/", foo)
http.ListenAndServe(":3000", nil)
}
func foo(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
}

测试:

1
2
3
4
5
6
$ curl -i localhost:3000
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 2
OK

返回JSON数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main
import (
"encoding/json"
"net/http"
)
type Profile struct {
Name string
Hobbies []string
}
func main() {
http.HandleFunc("/", foo)
http.ListenAndServe(":3000", nil)
}
func foo(w http.ResponseWriter, r *http.Request) {
profile := Profile{"Alex", []string{"snowboarding", "programming"}}
js, err := json.Marshal(profile)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(js)
}

测试:

1
2
3
4
5
6
$ curl -i localhost:3000
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 56
{"Name":"Alex",Hobbies":["snowboarding","programming"]}

返回XML数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main
import (
"encoding/xml"
"net/http"
)
type Profile struct {
Name string
Hobbies []string `xml:"Hobbies>Hobby"`
}
func main() {
http.HandleFunc("/", foo)
http.ListenAndServe(":3000", nil)
}
func foo(w http.ResponseWriter, r *http.Request) {
profile := Profile{"Alex", []string{"snowboarding", "programming"}}
x, err := xml.MarshalIndent(profile, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/xml")
w.Write(x)
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
$ curl -i localhost:3000
HTTP/1.1 200 OK
Content-Type: application/xml
Content-Length: 128
<Profile>
<Name>Alex</Name>
<Hobbies>
<Hobby>snowboarding</Hobby>
<Hobby>programming</Hobby>
</Hobbies>
</Profile>

文件服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main
import (
"net/http"
"path"
)
func main() {
http.HandleFunc("/", foo)
http.ListenAndServe(":3000", nil)
}
func foo(w http.ResponseWriter, r *http.Request) {
// Assuming you want to serve a photo at 'images/foo.png'
fp := path.Join("images", "foo.png")
http.ServeFile(w, r, fp)
}

测试:

1
2
3
4
5
6
$ curl -I localhost:3000
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 236717
Content-Type: image/png
Last-Modified: Thu, 10 Oct 2013 22:23:26 GMT

使用HTML模版

模板文件:templates/index.html

templates/index.html
1
2
<h1>Hello { { .Name } }</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main
import (
"html/template"
"net/http"
"path"
)
type Profile struct {
Name string
Hobbies []string
}
func main() {
http.HandleFunc("/", foo)
http.ListenAndServe(":3000", nil)
}
func foo(w http.ResponseWriter, r *http.Request) {
profile := Profile{"Alex", []string{"snowboarding", "programming"}}
fp := path.Join("templates", "index.html")
tmpl, err := template.ParseFiles(fp)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := tmpl.Execute(w, profile); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}

测试:

1
2
3
4
5
6
7
$ curl -i localhost:3000
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 84
<h1>Hello Alex</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>

使用HTML模板生成字符串

除了上面的把http.ResponseWriter作为模版的执行参数,还可以使用buffer得到渲染的结果。

1
2
3
4
5
6
7
...
buf := new(bytes.Buffer)
if err := tmpl.Execute(buf, profile); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
templateString := buf.String()
...

使用嵌套的模版

文件:templates/layout.html

templates/layout.html
1
2
3
4
5
6
7
8
<html>
<head>
<title>{ { template "title" . } } </title>
</head>
<body
{ { template "content" . } }
</body>
</html>

文件:templates/index.html

templates/index.html
1
2
3
4
5
6
{ { define "title" } }An example layout{ { end } }
{ { define "content" } }
<h1>Hello { { .Name } }</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
{ { end } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main
import (
"html/template"
"net/http"
"path"
)
type Profile struct {
Name string
Hobbies []string
}
func main() {
http.HandleFunc("/", foo)
http.ListenAndServe(":3000", nil)
}
func foo(w http.ResponseWriter, r *http.Request) {
profile := Profile{"Alex", []string{"snowboarding", "programming"}}
lp := path.Join("templates", "layout.html")
fp := path.Join("templates", "index.html")
// Note that the layout file must be the first parameter in ParseFiles
tmpl, err := template.ParseFiles(lp, fp)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := tmpl.Execute(w, profile); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ curl -i localhost:3000
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 180
<html>
<head>
<title>An example layout</title>
</head>
<body>
<h1>Hello Alex</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</body>
</html>