无法使用GO正确序列化json数据



我第一次使用Go,我试图创建一个使用json接收收据的web应用程序,然后为该收据生成一个唯一的id,并分配一些"点";和那张收据有什么关系。但是,当我在表单中输入json收据并点击"提交"时;我得到以下错误:无效字符'r'查找值的开始。

我打印了我的收据之后,它应该填充,它是空的,所以我意识到我只是没有正确序列化它。然而,我不知道如何序列化json正确使用go。

这是我的main.go

package main
import (
"encoding/json"
"fmt"
"html/template"
"math"
"math/rand"
"net/http"
"strconv"
"strings"
)
type Receipt struct {
Retailer     string `json:"retailer"`
PurchaseDate string `json:"purchaseDate"`
PurchaseTime string `json:"purchaseTime"`
Items        []Item `json:"items"`
Total        string `json:"total"`
}
type Item struct {
ShortDescription string `json:"shortDescription"`
Price            string `json:"price"`
}
type ReceiptResult struct {
ID     string
Points int
}
func main() {
http.HandleFunc("/", receiptHandler)
http.ListenAndServe(":8080", nil)
}
func receiptHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
var receipt Receipt
err := json.NewDecoder(r.Body).Decode(&receipt)
j, _ := json.MarshalIndent(receipt, "", "    ")
fmt.Println(string(j))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
result := processReceipt(receipt)
tmpl := template.Must(template.ParseFiles("result.html"))
tmpl.Execute(w, result)
} else {
tmpl := template.Must(template.ParseFiles("index.html"))
tmpl.Execute(w, nil)
}
}
func processReceipt(receipt Receipt) ReceiptResult {
var result ReceiptResult
result.ID = generateID()
result.Points += len(strings.ReplaceAll(receipt.Retailer, " ", ""))
result.Points += roundDollarPoints(receipt.Total)
result.Points += quarterPoints(receipt.Total)
result.Points += itemPoints(receipt.Items)
result.Points += itemDescriptionPoints(receipt.Items)
return result
}
func generateID() string {
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
b := make([]byte, 10)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
func roundDollarPoints(total string) int {
f, err := strconv.ParseFloat(total, 64)
if err != nil {
return 0
}
if math.Mod(f, 1) == 0 {
return 50
}
return 0
}
func quarterPoints(total string) int {
f, err := strconv.ParseFloat(total, 64)
if err != nil {
return 0
}
if math.Mod(f*100, 25) == 0 {
return 25
}
return 0
}
func itemPoints(items []Item) int {
return len(items) / 2 * 5
}
func itemDescriptionPoints(items []Item) int {
var points int
for _, item := range items {
trimmedLength := len(strings.TrimSpace(item.ShortDescription))
if trimmedLength%3 == 0 {
price, err := strconv.ParseFloat(item.Price, 64)
if err != nil {
continue
}
points += int(math.Ceil(price * 0.2))
}
}
return points
}

这是我的index.html,这是我的主页

<!DOCTYPE html>
<html>
<head>
<title>Receipt Processor</title>
</head>
<body>
<h1>Receipt Processor</h1>
<form method="POST" action="/">
<label for="receipt">Receipt JSON:</label>
<textarea id="receipt" name="receipt" rows="10" cols="50"></textarea><br><br>
<input type="submit" value="Process Receipt">
</form>
</body>
</html>

这是我的result。html这是我提交json后应该被发送到的页面

<!DOCTYPE html>
<html>
<head>
<title>Receipt Processor Result</title>
</head>
<body>
<h1>Receipt Processor Result</h1>
<p>Receipt ID: {{.ID}}</p>
<p>Points Earned: {{.Points}}</p>
</body>
</html>

这是我一直用于测试的json:

{
"retailer": "M&M Corner Market",
"purchaseDate": "2022-03-20",
"purchaseTime": "14:33",
"items": [
{
"shortDescription": "Gatorade",
"price": "2.25"
},
{
"shortDescription": "Doritos",
"price": "1.99"
},
{
"shortDescription": "Hershey's Chocolate Bar",
"price": "1.50"
},
{
"shortDescription": "Coca-Cola",
"price": "2.25"
}
],
"total": "8.99"
}

当您按下HTML页面上的Process Receipt按钮时,表单得到POST,浏览器将使用HTTP POST请求发送表单数据,其中主体将是URL编码的表单数据,如下所示:

receipt=%7B%0D%0A++%22retailer%22%3A+%22M%26M+Corner+Market%22%2C%0D%0A++%22purchaseDate%22%3A+%222022-03-20...

正文将为收据文本区域的内容。

在服务器端,在你的处理程序中,获得收据文本区域的值,使用Request.FormValue(),传递表单输入的name:

input := r.FormValue("receipt")

返回string,因此您可以使用strings.NewReader(),您可以将其传递给json.NewDecoder():

input := r.FormValue("receipt")
var receipt Receipt
err := json.NewDecoder(strings.NewReader(input)).Decode(&receipt)

修改后,输出将是:

{
"retailer": "Mu0026M Corner Market",
"purchaseDate": "2022-03-20",
"purchaseTime": "14:33",
"items": [
{
"shortDescription": "Gatorade",
"price": "2.25"
},
{
"shortDescription": "Doritos",
"price": "1.99"
},
{
"shortDescription": "Hershey's Chocolate Bar",
"price": "1.50"
},
{
"shortDescription": "Coca-Cola",
"price": "2.25"
}
],
"total": "8.99"
}

和HTML响应文档:

收货处理结果

收货编号:GUaaGCCGFs

累计积分:26

另外,我知道这只是一个例子,但是不要在处理程序中解析模板。在应用程序启动时解析它们,然后在处理程序中执行它们。使用"模板"费时太长了。在Golang

中为客户端生成动态网页。还请注意,您的浏览器也将生成一个/favicon.ico请求,该请求也将定向到receiptHandler(),但它不会在这里造成麻烦。

最新更新