在以下Web Development with Go by Shiju Varghese示例中,该示例用于为每个HTTP请求使用新的MongoDB会话实现HTTP服务器:
为什么在json
函数中使用Decode
包的PostCategory
方法?
为什么在json
函数中使用Marshal
包的GetCategories
方法?
起初我认为Decode
中的PostCategory
和Marshal
中的GetCategories
彼此相反,但后来我发现有Unmarshal
方法,可能是Encode
包中的json
个方法。所以我之前问过a question。
这是程序
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
var session *mgo.Session
type (
Category struct {
Id bson.ObjectId `bson:"_id,omitempty"`
Name string
Description string
}
DataStore struct {
session *mgo.Session
}
)
//Close mgo.Session
func (d *DataStore) Close() {
d.session.Close()
}
//Returns a collection from the database.
func (d *DataStore) C(name string) *mgo.Collection {
return d.session.DB("taskdb").C(name)
}
//Create a new DataStore object for each HTTP request
func NewDataStore() *DataStore {
ds := &DataStore{
session: session.Copy(),
}
return ds
}
//Insert a record
func PostCategory(w http.ResponseWriter, r *http.Request) {
var category Category
// Decode the incoming Category json
err := json.NewDecoder(r.Body).Decode(&category)
if err != nil {
panic(err)
}
ds := NewDataStore()
defer ds.Close()
//Getting the mgo.Collection
c := ds.C("categories")
//Insert record
err = c.Insert(&category)
if err != nil {
panic(err)
}
w.WriteHeader(http.StatusCreated)
}
//Read all records
func GetCategories(w http.ResponseWriter, r *http.Request) {
var categories []Category
ds := NewDataStore()
defer ds.Close()
//Getting the mgo.Collection
c := ds.C("categories")
iter := c.Find(nil).Iter()
result := Category{}
for iter.Next(&result) {
categories = append(categories, result)
}
w.Header().Set("Content-Type", "application/json")
j, err := json.Marshal(categories)
if err != nil {
panic(err)
}
w.WriteHeader(http.StatusOK)
w.Write(j)
}
func main() {
var err error
session, err = mgo.Dial("localhost")
if err != nil {
panic(err)
}
r := mux.NewRouter()
r.HandleFunc("/api/categories", GetCategories).Methods("GET")
r.HandleFunc("/api/categories", PostCategory).Methods("POST")
server := &http.Server{
Addr: ":8080",
Handler: r,
}
log.Println("Listening...")
server.ListenAndServe()
}
答案 0 :(得分:4)
我认为在这里使用json.NewDecoder
的主要原因是直接从响应的正文(r.Body
)读取,因为NewDecoder
需要io.Reader
作为输入。
您可以使用json.Unmarshal
,但是您必须首先将响应正文读入[]byte
并将该值传递给json.Unmarshal
。 NewDecoder
在这里更方便。
答案 1 :(得分:1)
TL; DR - Marshal
/ Unmarshal
获取并返回字节切片,而Encode
/ Decode
做同样的事情,但是读取来自流的字节,例如网络连接(读者和作者)。
encoding/json
包使用Encoder
和Decoder
类型来处理数据的流,即io.Reader
和{ {3}}的。这意味着您可以直接从网络套接字(或者在这种情况下实现io.Reader
的HTTP主体)获取数据,并在字节进入时将其转换为JSON。这样做,我们可以继续并开始在任何数据可用之后但在我们收到整个文档之前处理JSON(在使用大文档的慢速网络连接上,这可以节省我们很多时间,并且对于一些具有“无限大小”文档流的流协议这绝对是必要的!)
Marshal
和Unmarshal
对字节切片进行操作,这意味着您必须先将整个JSON文档放在内存中才能使用它们。在您的示例中,作者使用Marshal,因为他们已经有一个[]byte
切片,因此使用字节切片构造缓冲区没有意义,然后使用该缓冲区创建一个编码器,然后调用encode:相反,他们只能让元帅为他们做到了。
实际上,Marshal / Unmarshal只是编码器和解码器之上的便捷方法。如果我们看一下io.Writer
,我们会发现它只是构建一个编码器(或编码器的内部表示,但相信我,它们是相同的,如果你想要证明你可以看看source for Unmarshal并看到它还创建了一个encodeState
),然后返回输出字节:
func Marshal(v interface{}) ([]byte, error) {
e := &encodeState{}
err := e.marshal(v)
if err != nil {
return nil, err
}
return e.Bytes(), nil
}