Go语言编程笔记17:Web Service

本文是Go语言编程笔记的第17篇,介绍如何使用Go构建Web Service,包括XML和JSON的解析与编码,RESTful API设计,访问令牌和登录机制。文中还探讨了在Go中处理大型XML和JSON文件的方法,并提供了相关工具和参考资料。
摘要由CSDN通过智能技术生成

Go语言编程笔记17:Web Service

image-20211108153040805

图源:wallpapercave.com

通过一系列文章,我介绍了如何用Go语言构建一个Web应用,准确的说是一个网站。事实上并非所有的Web应用都是以网站的形式存在,其中相当一部分是Web Service,相比前者,后者的应用范围更广泛,它的前端可能是纯Js编写的网站前端,也可能是移动APP,甚至是另一个Web应用。

所以这篇文章将介绍如何构建一个Web Service。

这里的Web Service概念和Apache之类的有所不同,它指那些通过API方式提供服务的Web应用。

在说明Web Service之前,要先说明两种流行的文本传输格式:XML和JSON,事实上大部分Web Service都会使用这两者其中之一作为API的载体。

XML

来看一个典型的XML文本:

<?xml version="1.0" encoding="UTF-8"?>
<article id="1" uid="1">
	<Content>this is a art&#39;s content.</Content>
	<comments>
		<comment id="1" uid="1">first comment content.</comment>
		<comment id="2" uid="1">second comment content.</comment>
		<comment id="3" uid="2">third comment content.</comment>
	</comments>
</article>

Content标签中的乱码是对'符号的转义。

解析

XML本身并不复杂,和HTML类似,都是由一系列标签组成。关于XML的相关定义这里不过多解释,直接看如何用Go语言解析:

package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

type Article struct {
   
	XMLName  xml.Name  `xml:"article"`
	Id       int       `xml:"id,attr"`
	Content  string    `xml:content`
	Comments []Comment `xml:"comments>comment"`
	Uid      int       `xml:"uid,attr"`
}

func (a *Article) String() string {
   
	var comments []string
	for _, c := range a.Comments {
   
		comments = append(comments, c.String())
	}
	scs := strings.Join(comments, ",")
	return fmt.Sprintf("Article(Id:%d,Content:'%s',Comments:[%s],Uid:%d)", a.Id, a.Content, scs, a.Uid)
}

type Comment struct {
   
	XMLName xml.Name `xml:"comment"`
	Id      int      `xml:"id,attr"`
	Content string   `xml:",chardata"`
	Uid     int      `xml:"uid,attr"`
}

func (c *Comment) String() string {
   
	return fmt.Sprintf("Comment(Id:%d,Content:'%s',Uid:%d)", c.Id, c.Content, c.Uid)
}

func main() {
   
	fopen, err := os.Open("art.xml")
	if err != nil {
   
		panic(err)
	}
	defer fopen.Close()
	content, err := ioutil.ReadAll(fopen)
	if err != nil && err != io.EOF {
   
		panic(err)
	}
	art := Article{
   }
	err = xml.Unmarshal(content, &art)
	if err != nil {
   
		panic(err)
	}
	fmt.Println(art.String())
}

Go用于处理XML格式的包为encoding/xml

和在Go语言编程笔记16:存储数据 - 魔芋红茶’s blog (icexmoon.xyz)中介绍的ORM类似,要将一个XML文本解析到Go的结构体,需要建立从XML到结构体的映射关系,这种映射关系同样体现为结构体的字段标签。

所谓的“字段标签”实际上就是结构体字段后用特殊单引号标注的部分。

字段标签有这么几种:

  • xml:"<tag_name>",指代当前标签中的名称为tag_name的子标签的值。
  • xml:"<attr_name>,attr",指代当前标签的名称为attr_name的属性。
  • xml:",innerxml",指代当前标签包含的XML文本。
  • xml:",chardata",指代当前标签的值。
  • xml:"a>b>c",指代当前标签下包含的a标签包含的b标签包含的c标签,使用此标注可以直接让字段跨越几个层级对应到某个或某几个字标签。

比较特别的是,一般情况下解析器会使用结构的名称来匹配标签,比如用结构体Article匹配<article>标签,但如果结构体名称和标签不一致,就需要通过给结构体添加一个额外字段XMLName来指定对应的标签:

type Article struct {
   
	XMLName  xml.Name  `xml:"article"`
	...
}

XMLName的类型是xml.Name,字段标签是xml:"<tag_name>"

通过字段标签构建好映射关系后就简单了,从文件或者数据流读取数据到字符串或者字节序列,然后调用xml.Unmarshal函数进行解码即可。

大多数情况下用这种方式解析XML文本都是没有问题的,但有时候对于某些内容巨大的XML文件或者字节流,这样处理就不合适了,可能完整读取XML到内存都会是一项艰巨的任务。

所以xml包还提供“逐句解析”的选项,这样做可以在节省内存的前提下解析大容量XML文本:

...
func main() {
   
	fopen, err := os.Open("art.xml")
	if err != nil {
   
		panic(err)
	}
	defer fopen.Close()
	d := xml.NewDecoder(fopen)
	var comments []Comment
	for {
   
		token, err := d.Token()
		if err == io.EOF {
   
			//xml解析完毕
			break
		}
		if err != nil {
   
			//解析出错
			panic(err)
		}
		switch node := token.(type) {
   
		case xml.StartElement
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值