DarrenWang

心向往之


  • 首页

  • 归档

Go如何使用session

发表于 2018-08-03 | 分类于 go开发

6.2 Go如何使用session

通过上一小节的介绍,我们知道session是在服务器端实现的一种用户和服务器之间认证的解决方案,目前Go标准包没有为session提供任何支持,这小节我们将会自己动手来实现go版本的session管理和创建。

session创建过程

session的基本原理是由服务器为每个会话维护一份信息数据,客户端和服务端依靠一个全局唯一的标识来访问这份数据,以达到交互的目的。当用户访问Web应用时,服务端程序会随需要创建session,这个过程可以概括为三个步骤:

  • 生成全局唯一标识符(sessionid);
  • 开辟数据存储空间。一般会在内存中创建相应的数据结构,但这种情况下,系统一旦掉电,所有的会话数据就会丢失,如果是电子商务类网站,这将造成严重的后果。所以为了解决这类问题,你可以将会话数据写到文件里或存储在数据库中,当然这样会增加I/O开销,但是它可以实现某种程度的session持久化,也更有利于session的共享;
  • 将session的全局唯一标示符发送给客户端。
    阅读全文 »

小结

发表于 2018-08-03 | 分类于 go开发

6.5 小结

这章我们学习了什么是session,什么是cookie,以及他们两者之间的关系。但是目前Go官方标准包里面不支持session,所以我们设计了一个session管理器,实现了session从创建到销毁的整个过程。然后定义了Provider的接口,使得可以支

阅读全文 »

文本文件处理

发表于 2018-08-03 | 分类于 go开发

7 文本处理

Web开发中对于文本处理是非常重要的一部分,我们往往需要对输出或者输入的内容进行处理,这里的文本包括字符串、数字、Json、XMl等等。Go语言作为一门高性能的语言,对这些文本的处理都有官方的标准库来支持。而且在你使用中你会发现Go标准库的一些设计相当的巧妙,而且对于使用者来说也很方便就能处理这些文本。本章我们将通过四个小节的介绍,让用户对Go语言处理文本有一个很好的认识。
XML是目前很多标准接口的交互语言,很多时候和一些Java编写的webserver进行交互都是基于XML标准进行交互,7.1小节将介绍如何处理XML文本,我们使用XML之后发现它太复杂了,现在很多互联网企业对外的API大多数采用了JSON格式,这种格式描述简单,但是又能很好的表达意思,7.2小节我们将讲述如何来处理这样的JSON格式数据。正则是一个让人又爱又恨的工具,它处理文本的能力非常强大,我们在前面表单验证里面已经有所领略它的强大,7.3小节将详细的更深入的讲解如何利用好Go的正则。Web开发中一个很重要的部分就是MVC分离,在Go语言的Web开发中V有一个专门的包来支持template,7.4小节将详细的讲解如何使用模版来进行输出内容。7.5小节将详细介绍如何进行文件和文件夹的操作。7.6小结介绍了字符串的相关操作。

目录

阅读全文 »

XML处理

发表于 2018-08-03 | 分类于 go开发

7.1 XML处理

XML作为一种数据交换和信息传递的格式已经十分普及。而随着Web服务日益广泛的应用,现在XML在日常的开发工作中也扮演了愈发重要的角色。这一小节, 我们将就Go语言标准包中的XML相关处理的包进行介绍。
这个小节不会涉及XML规范相关的内容(如需了解相关知识请参考其他文献),而是介绍如何用Go语言来编解码XML文件相关的知识。
假如你是一名运维人员,你为你所管理的所有服务器生成了如下内容的xml的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
<!-- more -->
<?xml version="1.0" encoding="utf-8"?>
<servers version="1">
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
</servers>

上面的XML文档描述了两个服务器的信息,包含了服务器名和服务器的IP信息,接下来的Go例子以此XML描述的信息进行操作。

解析XML

如何解析如上这个XML文件呢? 我们可以通过xml包的Unmarshal函数来达到我们的目的

1
func Unmarshal(data []byte, v interface{}) error

data接收的是XML数据流,v是需要输出的结构,定义为interface,也就是可以把XML转换为任意的格式。我们这里主要介绍struct的转换,因为struct和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
30
31
32
33
34
35
36
37
38
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
)
type Recurlyservers struct {
XMLName xml.Name `xml:"servers"`
Version string `xml:"version,attr"`
Svs []server `xml:"server"`
Description string `xml:",innerxml"`
}
type server struct {
XMLName xml.Name `xml:"server"`
ServerName string `xml:"serverName"`
ServerIP string `xml:"serverIP"`
}
func main() {
file, err := os.Open("servers.xml") // For read access.
if err != nil {
fmt.Printf("error: %v", err)
return
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Printf("error: %v", err)
return
}
v := Recurlyservers{}
err = xml.Unmarshal(data, &v)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Println(v)
}

XML本质上是一种树形的数据格式,而我们可以定义与之匹配的go 语言的 struct类型,然后通过xml.Unmarshal来将xml中的数据解析成对应的struct对象。如上例子输出如下数据

1
2
3
4
5
6
7
8
9
10
{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
}

上面的例子中,将xml文件解析成对应的struct对象是通过xml.Unmarshal来完成的,这个过程是如何实现的?可以看到我们的struct定义后面多了一些类似于xml:"serverName"这样的内容,这个是struct的一个特性,它们被称为 struct tag,它们是用来辅助反射的。我们来看一下Unmarshal的定义:

1
func Unmarshal(data []byte, v interface{}) error

我们看到函数定义了两个参数,第一个是XML数据流,第二个是存储的对应类型,目前支持struct、slice和string,XML包内部采用了反射来进行数据的映射,所以v里面的字段必须是导出的。Unmarshal解析的时候XML元素和字段怎么对应起来的呢?这是有一个优先级读取流程的,首先会读取struct tag,如果没有,那么就会对应字段名。必须注意一点的是解析的时候tag、字段名、XML元素都是大小写敏感的,所以必须一一对应字段。
Go语言的反射机制,可以利用这些tag信息来将来自XML文件中的数据反射成对应的struct对象,关于反射如何利用struct tag的更多内容请参阅reflect中的相关内容。
解析XML到struct的时候遵循如下的规则:

  • 如果struct的一个字段是string或者[]byte类型且它的tag含有",innerxml",Unmarshal将会将此字段所对应的元素内所有内嵌的原始xml累加到此字段上,如上面例子Description定义。最后的输出是

    1
    2
    3
    4
    5
    6
    7
    8
    <server>
    <serverName>Shanghai_VPN</serverName>
    <serverIP>127.0.0.1</serverIP>
    </server>
    <server>
    <serverName>Beijing_VPN</serverName>
    <serverIP>127.0.0.2</serverIP>
    </server>
  • 如果struct中有一个叫做XMLName,且类型为xml.Name字段,那么在解析的时候就会保存这个element的名字到该字段,如上面例子中的servers。

  • 如果某个struct字段的tag定义中含有XML结构中element的名称,那么解析的时候就会把相应的element值赋值给该字段,如上servername和serverip定义。
  • 如果某个struct字段的tag定义了中含有",attr",那么解析的时候就会将该结构所对应的element的与字段同名的属性的值赋值给该字段,如上version定义。
  • 如果某个struct字段的tag定义 型如"a>b>c",则解析的时候,会将xml结构a下面的b下面的c元素的值赋值给该字段。
  • 如果某个struct字段的tag定义了"-",那么不会为该字段解析匹配任何xml数据。
  • 如果struct字段后面的tag定义了",any",如果他的子元素在不满足其他的规则的时候就会匹配到这个字段。
  • 如果某个XML元素包含一条或者多条注释,那么这些注释将被累加到第一个tag含有”,comments”的字段上,这个字段的类型可能是[]byte或string,如果没有这样的字段存在,那么注释将会被抛弃。
    上面详细讲述了如何定义struct的tag。 只要设置对了tag,那么XML解析就如上面示例般简单,tag和XML的element是一一对应的关系,如上所示,我们还可以通过slice来表示多个同级元素。

    注意: 为了正确解析,go语言的xml包要求struct定义中的所有字段必须是可导出的(即首字母大写)

    输出XML

    假若我们不是要解析如上所示的XML文件,而是生成它,那么在go语言中又该如何实现呢? xml包中提供了Marshal和MarshalIndent两个函数,来满足我们的需求。这两个函数主要的区别是第二个函数会增加前缀和缩进,函数的定义如下所示:
    1
    2
    func Marshal(v interface{}) ([]byte, error)
    func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

两个函数第一个参数是用来生成XML的结构定义类型数据,都是返回生成的XML数据流。
下面我们来看一下如何输出如上的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
30
31
32
33
34
35
36
37
38
39
40
package main
import (
"encoding/xml"
"fmt"
"os"
)
type Servers struct {
XMLName xml.Name `xml:"servers"`
Version string `xml:"version,attr"`
Svs []server `xml:"server"`
}
type server struct {
ServerName string `xml:"serverName"`
ServerIP string `xml:"serverIP"`
}
func main() {
v := &Servers{Version: "1"}
v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"})
v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"})
output, err := xml.MarshalIndent(v, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
}
os.Stdout.Write([]byte(xml.Header))
os.Stdout.Write(output)
}
```
上面的代码输出如下信息:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<servers version="1">
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
</servers>

和我们之前定义的文件的格式一模一样,之所以会有os.Stdout.Write([]byte(xml.Header)) 这句代码的出现,是因为xml.MarshalIndent或者xml.Marshal输出的信息都是不带XML头的,为了生成正确的xml文件,我们使用了xml包预定义的Header变量。
我们看到Marshal函数接收的参数v是interface{}类型的,即它可以接受任意类型的参数,那么xml包,根据什么规则来生成相应的XML文件呢?

  • 如果v是 array或者slice,那么输出每一个元素,类似value
  • 如果v是指针,那么会Marshal指针指向的内容,如果指针为空,什么都不输出
  • 如果v是interface,那么就处理interface所包含的数据
  • 如果v是其他数据类型,就会输出这个数据类型所拥有的字段信息
    生成的XML文件中的element的名字又是根据什么决定的呢?元素名按照如下优先级从struct中获取:
  • 如果v是struct,XMLName的tag中定义的名称
  • 类型为xml.Name的名叫XMLName的字段的值
  • 通过struct中字段的tag来获取
  • 通过struct的字段名用来获取
  • marshall的类型名称
    我们应如何设置struct 中字段的tag信息以控制最终xml文件的生成呢?
  • XMLName不会被输出
  • tag中含有"-"的字段不会输出
  • tag中含有"name,attr",会以name作为属性名,字段值作为值输出为这个XML元素的属性,如上version字段所描述
  • tag中含有",attr",会以这个struct的字段名作为属性名输出为XML元素的属性,类似上一条,只是这个name默认是字段名了。
  • tag中含有",chardata",输出为xml的 character data而非element。
  • tag中含有",innerxml",将会被原样输出,而不会进行常规的编码过程
  • tag中含有",comment",将被当作xml注释来输出,而不会进行常规的编码过程,字段值中不能含有”–”字符串
  • tag中含有"omitempty",如果该字段的值为空值那么该字段就不会被输出到XML,空值包括:false、0、nil指针或nil接口,任何长度为0的array, slice, map或者string
  • tag中含有"a>b>c",那么就会循环输出三个元素a包含b,b包含c,例如如下代码就会输出
    1
    2
    3
    4
    5
    6
    FirstName string   `xml:"name>first"`
    LastName string `xml:"name>last"`
    <name>
    <first>Asta</first>
    <last>Xie</last>
    </name>

上面我们介绍了如何使用Go语言的xml包来编/解码XML文件,重要的一点是对XML的所有操作都是通过struct tag来实现的,所以学会对struct tag的运用变得非常重要,在文章中我们简要的列举了如何定义tag。更多内容或tag定义请参看相应的官方资料。

links

  • 目录
  • 上一节: 文本处理
  • 下一节: Json处理

JSON处理

发表于 2018-08-03 | 分类于 go开发

7.2 JSON处理

JSON(Javascript Object Notation)是一种轻量级的数据交换语言,以文字为基础,具有自我描述性且易于让人阅读。尽管JSON是Javascript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。JSON与XML最大的不同在于XML是一个完整的标记语言,而JSON不是。JSON由于比XML更小、更快,更易解析,以及浏览器的内建快速解析支持,使得其更适用于网络数据传输领域。目前我们看到很多的开放平台,基本上都是采用了JSON作为他们的数据交互的接口。既然JSON在Web开发中如此重要,那么Go语言对JSON支持的怎么样呢?Go语言的标准库已经非常好的支持了JSON,可以很容易的对JSON数据进行编、解码的工作。
前一小节的运维的例子用json来表示,结果描述如下:

1
{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}

本小节余下的内容将以此JSON数据为基础,来介绍go语言的json包对JSON数据的编、解码。

解析JSON

阅读全文 »

正则处理

发表于 2018-08-03 | 分类于 go开发

7.3 正则处理

正则表达式是一种进行模式匹配和文本操纵的复杂而又强大的工具。虽然正则表达式比纯粹的文本匹配效率低,但是它却更灵活。按照它的语法规则,随需构造出的匹配模式就能够从原始文本中筛选出几乎任何你想要得到的字符组合。如果你在Web开发中需要从一些文本数据源中获取数据,那么你只需要按照它的语法规则,随需构造出正确的模式字符串就能够从原数据源提取出有意义的文本信息。
Go语言通过regexp标准包为正则表达式提供了官方支持,如果你已经使用过其他编程语言提供的正则相关功能,那么你应该对Go语言版本的不会太陌生,但是它们之间也有一些小的差异,因为Go实现的是RE2标准,除了\C,详细的语法描述参考:http://code.google.com/p/re2/wiki/Syntax
其实字符串处理我们可以使用strings包来进行搜索(Contains、Index)、替换(Replace)和解析(Split、Join)等操作,但是这些都是简单的字符串操作,他们的搜索都是大小写敏感,而且固定的字符串,如果我们需要匹配可变的那种就没办法实现了,当然如果strings包能解决你的问题,那么就尽量使用它来解决。因为他们足够简单、而且性能和可读性都会比正则好。

阅读全文 »

文件操作

发表于 2018-08-03 | 分类于 go开发

7.5 文件操作

在任何计算机设备中,文件是都是必须的对象,而在Web编程中,文件的操作一直是Web程序员经常遇到的问题,文件操作在Web应用中是必须的,非常有用的,我们经常遇到生成文件目录,文件(夹)编辑等操作,现在我把Go中的这些操作做一详细总结并实例示范如何使用。

目录操作

阅读全文 »

小结

发表于 2018-08-03 | 分类于 go开发

7.7 小结

这一章给大家介绍了一些文本处理的工具,包括XML、JSON、正则和模板技术,XML和JSON是数据交互的工具,通过XML和JSON你可以表达各种含义,通过正则你可以处理文本(搜索、替换、截取),通过模板技术你可以展现这些数据给用户。这些都是你开发Web应用过程中需要用到的技术,通过这个小节的介绍你能够了解如何处理文本、展现文本。

阅读全文 »

字符串处理

发表于 2018-08-03 | 分类于 go开发

7.6 字符串处理

字符串在我们平常的Web开发中经常用到,包括用户的输入,数据库读取的数据等,我们经常需要对字符串进行分割、连接、转换等操作,本小节将通过Go标准库中的strings和strconv两个包中的函数来讲解如何进行有效快速的操作。

字符串操作

阅读全文 »

Web服务

发表于 2018-08-03 | 分类于 go开发

8 Web服务

Web服务可以让你在HTTP协议的基础上通过XML或者JSON来交换信息。如果你想知道上海的天气预报、中国石油的股价或者淘宝商家的一个商品信息,你可以编写一段简短的代码,通过抓取这些信息然后通过标准的接口开放出来,就如同你调用一个本地函数并返回一个值。
Web服务背后的关键在于平台的无关性,你可以运行你的服务在Linux系统,可以与其他Windows的asp.net程序交互,同样的,也可以通过同一个接口和运行在FreeBSD上面的JSP无障碍地通信。
目前主流的有如下几种Web服务:REST、SOAP。

阅读全文 »
1…456…10

王梦涛

100 日志
4 分类
4 标签
GitHub Weibo
© 2016 – 2018 王梦涛
由 Hexo 强力驱动 v3.6.0
|
主题 – NexT.Pisces v6.3.0