Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Golang语言社区--go语言编写Web程序

Golang语言社区--go语言编写Web程序

作者头像
李海彬
发布于 2018-03-07 13:49:46
发布于 2018-03-07 13:49:46
3.1K0
举报
文章被收录于专栏:Golang语言社区Golang语言社区

1. 简介

这个例子涉及到的技术:

  • 创建一个数据类型,含有load和save函数
  • 基于http包创建web程序
  • 基于template包的html模板技术
  • 使用regexp包验证用户输入
  • 使用闭包

假设读者有以下知识:

  • 基本的编程经验
  • web程序的基础技术(HTTP, HTML)
  • UNIX 命令行

2. 开始

首先,要有一个Linux, OS X, or FreeBSD系统,可以运行go程序。如果没有的话,可以安装一个虚拟机(如VirtualBox)或者 Virtual Private Server。

安装Go环境: (请参考 Installation Instructions).

创建一个新的目录,并且进入该目录:

代码语言:go
AI代码解释
复制
 $ mkdir ~/gowiki
  $ cd ~/gowiki

创建一个wiki.go文件,用你喜欢的编辑器打开,然后添加以下代码:

代码语言:go
AI代码解释
复制
package main
  
  import (
          "fmt"
          "io/ioutil"
          "os"
  )

我们从go的标准库导入fmt, ioutil 和 os包。 以后,当实现其他功能时,我们会根据需要导入更多包。

3. 数据结构

我们先定义一个结构类型,用于保存数据。wiki系统由一组互联的wiki页面组成,每个wiki页面包含内容和标题。我们定义wiki页面为结构page, 如下:

代码语言:go
AI代码解释
复制
 type page struct {
          title        string
          body        []byte
  }

类型[]byte表示一个byte slice。(参考Effective Go了解slices的更多信息) 成员body之所以定义为[]byte而不是string类型,是因为[]byte可以直接使用io包的功能。

结构体page描述了一个页面在内存中的存储方式。但是,如果要将数据保存到磁盘的话,还需要给page类型增加save方法:

代码语言:go
AI代码解释
复制
func (p *page) save() os.Error {
          filename := p.title + ".txt"
          return ioutil.WriteFile(filename, p.body, 0600)
  }

类型方法的签名可以这样解读:“save为page类型的方法,方法的调用者为page类型的指针变量p。该成员函数没有参数,返回值为os.Error,表示错误信息。”

该方法会将page结构的body部分保存到文本文件中。为了简单,我们用title作为文本文件的名字。

方法save的返回值类型为os.Error,对应WriteFile(标准库函数,将byte slice写到文件中)的返回值。通过返回os.Error值,可以判断发生错误的类型。如果没有错误,那么返回nil(指针、接口和其他一些类型的零值)。

WriteFile的第三个参数为八进制的0600,表示仅当前用户拥有新创建文件的读写权限。(参考Unix手册 open(2) )

下面的函数加载一个页面:

代码语言:go
AI代码解释
复制
 func loadPage(title string) *page {
          filename := title + ".txt"
          body, _ := ioutil.ReadFile(filename)
          return &page{title: title, body: body}
  }

函数loadPage根据页面标题从对应文件读取页面的内容,并且构造一个新的 page变量——对应一个页面。

go中函数(以及成员方法)可以返回多个值。标准库中的io.ReadFile在返回[]byte的同时还返回os.Error类型的错误信息。前面的代码中我们用下划线“_”丢弃了错误信息。

但是ReadFile可能会发生错误,例如请求的文件不存在。因此,我们给函数的返回值增加一个错误信息。

代码语言:go
AI代码解释
复制
 func loadPage(title string) (*page, os.Error) {
          filename := title + ".txt"
          body, err := ioutil.ReadFile(filename)
          if err != nil {
                  return nil, err
          }
          return &page{title: title, body: body}, nil
  }

现在调用者可以检测第二个返回值,如果为nil就表示成功装载页面。否则,调用者可以得到一个os.Error对象。(关于错误的更多信息可以参考os package documentation)

现在,我们有了一个简单的数据结构,可以保存到文件中,或者从文件加载。我们创建一个main函数,测试相关功能。

代码语言:go
AI代码解释
复制
  func main() {
          p1 := &page{title: "TestPage", body: []byte("This is a sample page.")}
          p1.save()
          p2, _ := loadPage("TestPage")
          fmt.Println(string(p2.body))
  }

编译后运行以上程序的话,会创建一个TestPage.txt文件,用于保存p1对应的页面内容。然后,从文件读取页面内容到p2,并且将p2的值打印到 屏幕。

可以用类似以下命令编译运行程序:

代码语言:go
AI代码解释
复制
$ 8g wiki.go
  $ 8l wiki.8
  $ ./8.out
  This is a sample page.

(命令8g和8l对应GOARCH=386。如果是amd64系统,可以用6g和6l)

点击这里查看我们当前的代码。

4. 使用http包

下面是一个完整的web server例子:

代码语言:go
AI代码解释
复制
package main
  
  import (
          "fmt"
          "http"
  )
  
  func handler(w http.ResponseWriter, r *http.Request) {
          fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
  }
  
  func main() {
          http.HandleFunc("/", handler)
          http.ListenAndServe(":8080", nil)
  }

在main函数中,http.HandleFunc设置所有对根目录请求的处理函数为handler。

然后调用http.ListenAndServe,在8080端口开始监听(第二个参数暂时可以忽略)。然后程序将阻塞,直到退出。

函数handler为http.HandlerFunc类型,它包含http.Conn和http.Request两个类型的参数。

其中http.Conn对应服务器的http连接,我们可以通过它向客户端发送数据。

类型为http.Request的参数对应一个客户端请求。其中r.URL.Path 为请求的地址,它是一个string类型变量。我们用[1:]在Path上创建 一个slice,对应"/"之后的路径名。

启动该程序后,通过浏览器访问以下地址:

代码语言:go
AI代码解释
复制
http://localhost:8080/monkeys

会看到以下输出内容:

代码语言:go
AI代码解释
复制
Hi there, I love monkeys!

5. 基于http提供wiki页面

要使用http包,先将其导入:

代码语言:go
AI代码解释
复制
import (
          "fmt"
          "http"
          "io/ioutil"
          "os"
  )

然后创建一个用于浏览wiki的函数:

代码语言:go
AI代码解释
复制
const lenPath = len("/view/")
  
  func viewHandler(w http.ResponseWriter, r *http.Request) {
          title := r.URL.Path[lenPath:]
          p, _ := loadPage(title)
          fmt.Fprintf(w, "
%s
%s
", p.title, p.body)
  }

首先,这个函数从r.URL.Path(请求URL的path部分)中解析页面标题。全局常量lenPath保存"/view/"的长度,它是请求路径的前缀部分。Path总是以"/view/"开头,去掉前面的6个字符就可以得到页面标题。

然后加载页面数据,格式化为简单的HTML字符串,写到c中,c是一个http.Conn类型的参数。

注意这里使用下划线“_”忽略loadPage的os.Error返回值。 这不是一种好的做法,此处是为了保持简单。我们将在后面考虑这个问题。

为了使用这个处理函数(handler),我们创建一个main函数。它使用viewHandler初始化http,把所有以/view/开头的请求转发给viewHandler处理。

代码语言:go
AI代码解释
复制
func main() {
          http.HandleFunc("/view/", viewHandler)
          http.ListenAndServe(":8080", nil)
  }

点击这里查看我们当前的代码。

让我们创建一些页面数据(例如as test.txt),编译,运行。

代码语言:go
AI代码解释
复制
$ echo "Hello world" > test.txt
  $ 8g wiki.go
  $ 8l wiki.8
  $ ./8.out

当服务器运行的时候,访问http://localhost:8080/view/test将显示一个页面,标题为“test”,内容为“Hello world”。

6. 编辑页面

编辑功能是wiki不可缺少的。现在,我们创建两个新的处理函数(handler):editHandler显示"edit page"表单(form),saveHandler保存表单(form)中的数据。

首先,将他们添加到main()函数中:

代码语言:go
AI代码解释
复制
func main() {
          http.HandleFunc("/view/", viewHandler)
          http.HandleFunc("/edit/", editHandler)
          http.HandleFunc("/save/", saveHandler)
          http.ListenAndServe(":8080", nil)
  }

函数editHandler加载页面(或者,如果页面不存在,创建一个空page 结构)并且显示为一个HTML表单(form)。

代码语言:go
AI代码解释
复制
func editHandler(w http.ResponseWriter, r *http.Request) {
          title := r.URL.Path[lenPath:]
          p, err := loadPage(title)
          if err != nil {
                  p = &page{title: title}
          }
          fmt.Fprintf(w, "
Editing %s
"+
                  "
"+
                  "
%s

"+
                  "
\"Save\"
"+
                  "
",
                  p.title, p.title, p.body)
  }

这个函数能够工作,但是硬编码的HTML非常丑陋。当然,我们有更好的办法。

7. template包

template包是GO语言标准库的一个部分。我们使用template将HTML存放在一个单独的文件中,可以更改编辑页面的布局而不用修改相关的GO代码。

首先,我们必须将template添加到导入列表:

代码语言:go
AI代码解释
复制
import (
          "http"
          "io/ioutil"
          "os"
          "template"
  )

创建一个包含HTML表单的模板文件。打开一个名为edit.html的新文件,添加下面的行:

代码语言:text
AI代码解释
复制
Editing {title}

  
  

  

{body|html}

  

  

修改editHandler,用模板替代硬编码的HTML。

代码语言:go
AI代码解释
复制
func editHandler(w http.ResponseWriter, r *http.Request) {
          title := r.URL.Path[lenPath:]
          p, err := loadPage(title)
          if err != nil {
                  p = &page{title: title}
          }
          t, _ := template.ParseFile("edit.html", nil)
          t.Execute(p, w)
  }

函数template.ParseFile读取edit.html的内容,返回*template.Template类型的数据。

方法t.Execute用p.title和p.body的值替换模板中所有的{title}和{body},并且把结果写到http.Conn。

注意,在上面的模板中我们使用{body|html}。|html部分请求模板引擎在输出body的值之前,先将它传到html格式化器(formatter),转义HTML字符(比如用>替换>)。 这样做,可以阻止用户数据破坏表单HTML。

既然我们删除了fmt.Sprintf语句,我们可以删除导入列表中的"fmt"。

使用模板技术,我们可以为viewHandler创建一个模板,命名为view.html。

代码语言:go
AI代码解释
复制
{title}

  
  
[edit]


  
  
{body}

修改viewHandler:

代码语言:go
AI代码解释
复制
 func viewHandler(w http.ResponseWriter, r *http.Request) {
          title := r.URL.Path[lenPath:]
          p, _ := loadPage(title)
          t, _ := template.ParseFile("view.html", nil)
          t.Execute(p, w)
  }

注意,在两个处理函数(handler)中使用了几乎完全相同的模板处理代码,我们可以把模板处理代码写成一个单独的函数,以消除重复。

代码语言:go
AI代码解释
复制
func viewHandler(w http.ResponseWriter, r *http.Request) {
          title := r.URL.Path[lenPath:]
          p, _ := loadPage(title)
          renderTemplate(w, "view", p)
  }
  
  func editHandler(w http.ResponseWriter, r *http.Request) {
          title := r.URL.Path[lenPath:]
          p, err := loadPage(title)
          if err != nil {
                  p = &page{title: title}
          }
          renderTemplate(w, "edit", p)
  }
  
  func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
          t, _ := template.ParseFile(tmpl+".html", nil)
          t.Execute(p, w)
  }

现在,处理函数(handler)代码更短、更加简单。

8. 处理不存在的页面

当你访问/view/APageThatDoesntExist的时候会发生什么?程序将会崩溃。因为我们忽略了loadPage返回的错误。请求页不存在的时候,应该重定向客户端到编辑页,这样新的页面将会创建。

代码语言:go
AI代码解释
复制
func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
          p, err := loadPage(title)
          if err != nil {
                  http.Redirect(w, r, "/edit/"+title, http.StatusFound)
                  return
          }
          renderTemplate(w, "view", p)
  }

函数http.Redirect添加HTTP状态码http.StatusFound (302)和报头Location到HTTP响应。

9. 储存页面

函数saveHandler处理表单提交。

代码语言:go
AI代码解释
复制
  func saveHandler(w http.ResponseWriter, r *http.Request) {
          title := r.URL.Path[lenPath:]
          body := r.FormValue("body")
          p := &page{title: title, body: []byte(body)}
          p.save()
          http.Redirect(w, r, "/view/"+title, http.StatusFound)
  }

页面标题(在URL中)和表单中唯一的字段,body,储存在一个新的page中。然后调用save()方法将数据写到文件中,并且将客户重定向到/view/页面。

FormValue返回值的类型是string,在将它添加到page结构前,我们必须将其转换为[]byte类型。我们使用[]byte(body)执行转换。

10. 错误处理

在我们的程序中,有几个地方的错误被忽略了。这是一种很糟糕的方式,特别是在错误发生后,程序会崩溃。更好的方案是处理错误并返回错误消息给用户。这样做,当错误发生后,服务器可以继续运行,用户也会得到通知。

首先,我们处理renderTemplate中的错误:

代码语言:go
AI代码解释
复制
  func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
          t, err := template.ParseFile(tmpl+".html", nil)
          if err != nil {
                  http.Error(w, err.String(), http.StatusInternalServerError)
                  return
          }
          err = t.Execute(p, w)
          if err != nil {
                  http.Error(w, err.String(), http.StatusInternalServerError)
          }
  }

函数http.Error发送一个特定的HTTP响应码(在这里表示“Internal Server Error”)和错误消息。

现在,让我们修复saveHandler:

代码语言:go
AI代码解释
复制
  func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
          body := r.FormValue("body")
          p := &page{title: title, body: []byte(body)}
          err := p.save()
          if err != nil {
                  http.Error(w, err.String(), http.StatusInternalServerError)
                  return
          }
          http.Redirect(w, r, "/view/"+title, http.StatusFound)
  }

p.save()中发生的任何错误都将报告给用户。

11. 模板缓存

代码中有一个低效率的地方:每次显示一个页面,renderTemplate都要调用ParseFile。更好的做法是在程序初始化的时候对每个模板调用ParseFile一次,将结果保存为*Template类型的值,在以后使用。

首先,我们创建一个全局map,命名为templates。templates用于储存*Template类型的值,使用string索引。

然后,我们创建一个init函数,init函数会在程序初始化的时候调用,在main函数之前。函数template.MustParseFile是ParseFile的一个封装,它不返回错误码,而是在错误发生的时候抛出(panic)一个错误。抛出错误(panic)在这里是合适的,如果模板不能加载,程序唯一能做的有意义的事就是退出。

代码语言:go
AI代码解释
复制
func init() { for _, tmpl := range []string{"edit", "view"} { templates[tmpl] = template.MustParseFile(tmpl+".html", nil) } }

使用带range语句的for循环访问一个常量数组中的每一个元素,这个常量数组中包含了我们想要加载的所有模板的名称。如果我们想要添加更多的模板,只要把模板名称添加的数组中就可以了。

修改renderTemplate函数,在templates中相应的Template上调用Execute方法:

代码语言:go
AI代码解释
复制
func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
          err := templates[tmpl].Execute(p, w)
          if err != nil {
                  http.Error(w, err.String(), http.StatusInternalServerError)
          }
  }

12. 验证

你可能已经发现,程序中有一个严重的安全漏洞:用户可以提供任意的路径在服务器上执行读写操作。为了消除这个问题,我们使用正则表达式验证页面的标题。

首先,添加"regexp"到导入列表。然后创建一个全局变量存储我们的验证正则表达式:

函数regexp.MustCompile解析并且编译正则表达式,返回一个regexp.Regexp对象。和template.MustParseFile类似,当表达式编译错误时,MustCompile抛出一个错误,而Compile在它的第二个返回参数中返回一个os.Error。

现在,我们编写一个函数,它从请求URL解析中解析页面标题,并且使用titleValidator进行验证:

代码语言:go
AI代码解释
复制
func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
          title = r.URL.Path[lenPath:]
          if !titleValidator.MatchString(title) {
                  http.NotFound(w, r)
                  err = os.NewError("Invalid Page Title")
          }
          return
  }

如果标题有效,它返回一个nil错误值。如果无效,它写"404 Not Found"错误到HTTP连接中,并且返回一个错误对象。

修改所有的处理函数,使用getTitle获取页面标题:

代码语言:go
AI代码解释
复制
func viewHandler(w http.ResponseWriter, r *http.Request) {
          title, err := getTitle(w, r)
          if err != nil {
                  return
          }
          p, err := loadPage(title)
          if err != nil {
                  http.Redirect(w, r, "/edit/"+title, http.StatusFound)
                  return
          }
          renderTemplate(w, "view", p)
  }
  
  func editHandler(w http.ResponseWriter, r *http.Request) {
          title, err := getTitle(w, r)
          if err != nil {
                  return
          }
          p, err := loadPage(title)
          if err != nil {
                  p = &page{title: title}
          }
          renderTemplate(w, "edit", p)
  }
  
  func saveHandler(w http.ResponseWriter, r *http.Request) {
          title, err := getTitle(w, r)
          if err != nil {
                  return
          }
          body := r.FormValue("body")
          p := &page{title: title, body: []byte(body)}
          err = p.save()
          if err != nil {
                  http.Error(w, err.String(), http.StatusInternalServerError)
                  return
          }
          http.Redirect(w, r, "/view/"+title, http.StatusFound)
  }

13. 函数文本和闭包

处理函数(handler)中捕捉错误是一些类似的重复代码。如果我们想将捕捉错误的代码封装成一个函数,应该怎么做?GO的函数文本提供了强大的抽象能力,可以帮我们做到这点。

首先,我们重写每个处理函数的定义,让它们接受标题字符串:

定义一个封装函数,接受上面定义的函数类型,返回http.HandlerFunc(可以传送给函数http.HandleFunc)。

代码语言:go
AI代码解释
复制
func makeHandler(fn func (http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
          return func(w http.ResponseWriter, r *http.Request) {
                  // Here we will extract the page title from the Request,
                  // and call the provided handler 'fn'
          }
  }

返回的函数称为闭包,因为它包含了定义在它外面的值。在这里,变量fn(makeHandler的唯一参数)被闭包包含。fn是我们的处理函数,save、edit、或view。

我们可以把getTitle的代码复制到这里(有一些小的变动):

代码语言:go
AI代码解释
复制
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
          return func(w http.ResponseWriter, r *http.Request) {
                  title := r.URL.Path[lenPath:]
                  if !titleValidator.MatchString(title) {
                          http.NotFound(w, r)
                          return
                  }
                  fn(w, r, title)
          }
  }

makeHandler返回的闭包是一个函数,它有两个参数,http.Conn和http.Request(因此,它是http.HandlerFunc)。闭包从请求路径解析title,使用titleValidator验证标题。如果title无效,使用函数http.NotFound将错误写到Conn。如果title有效,封装的处理函数fn将被调用,参数为Conn, Request, 和title。

在main函数中,我们用makeHandler封装所有处理函数:

代码语言:go
AI代码解释
复制
func main() {
          http.HandleFunc("/view/", makeHandler(viewHandler))
          http.HandleFunc("/edit/", makeHandler(editHandler))
          http.HandleFunc("/save/", makeHandler(saveHandler))
          http.ListenAndServe(":8080", nil)
  }

最后,我们可以删除处理函数中的getTitle,让处理函数更简单。

代码语言:go
AI代码解释
复制
func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
          p, err := loadPage(title)
          if err != nil {
                  http.Redirect(w, r, "/edit/"+title, http.StatusFound)
                  return
          }
          renderTemplate(w, "view", p)
  }
  
  func editHandler(w http.ResponseWriter, r *http.Request, title string) {
          p, err := loadPage(title)
          if err != nil {
                  p = &page{title: title}
          }
          renderTemplate(w, "edit", p)
  }
  
  func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
          body := r.FormValue("body")
          p := &page{title: title, body: []byte(body)}
          err := p.save()
          if err != nil {
                  http.Error(w, err.String(), http.StatusInternalServerError)
                  return
          }
          http.Redirect(w, r, "/view/"+title, http.StatusFound)
  }

14. 试试!

点击这里查看最终的代码

重新编译代码,运行程序:

代码语言:go
AI代码解释
复制
$ 8g wiki.go
  $ 8l wiki.8
  $ ./8.out

访问http://localhost:8080/view/ANewPage将会出现一个编辑表单。你可以输入一些文版,点击“Save”,重定向到新的页面。

15. 其他任务

这里有一些简单的任务,你可以自己解决:

  • 把模板文件存放在tmpl/目录,页面数据存放在data/目录。
  • 增加一个处理函数(handler),将对根目录的请求重定向到/view/FrontPage。
  • 修饰页面模板,使其成为有效的HTML文件。添加CSS规则。
  • 实现页内链接。将[PageName]修改为PageName。(提示:可以使用regexp.ReplaceAllFunc达到这个效果)

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Go语言写Web 应用程序
介绍 涵盖内容: 为载入和保存方法创建一个数据结构体 引用http包来创建一个web应用 引用template包来处理HTML模板 引用regexp包来验证用户的输入 引用 闭包操作 可能涉及到的知识: 设计经验 明白基础的web技术(HTTP,HTML) 一些UNIX命令行知识 从这里开始 你要有一个可以运行Go语言的计算机或虚拟机,怎么样安装Go,请参考安装Go教程。首先创建一个目录,在目录下创建一个wiki.go文件,用你喜欢的编辑器打开并输入以下内容: package main import (
李海彬
2018/03/22
8150
Go语言写Web 应用程序
Go语言写Web 应用程序
绍涵盖内容: 为载入和保存方法创建一个数据结构体 引用http包来创建一个web应用 引用template包来处理HTML模板 引用regexp包来验证用户的输入 引用 闭包操作 可能涉及到的知识: 设计经验 明白基础的web技术(HTTP,HTML) 一些UNIX命令行知识 从这里开始 你要有一个可以运行Go语言的计算机或虚拟机,怎么样安装Go,请参考安装Go教程。首先创建一个目录,在目录下创建一个wiki.go文件,用你喜欢的编辑器打开并输入以下内容: package main impo
李海彬
2018/03/19
8890
Go语言写Web 应用程序
Golang语言写Web 应用程序
view.html <h1>www.golangweb.com</h1> <h1>{{.Title |html}}</h1> <div>{{printf "%s" .Body |html}}</div> <p>[<a href="/edit/{{.Title |html}}">edit</a>]</p> edit.html <h1>Editing {{.Title |html}}</h1> <form action="/save/{{.Title |html}}" method="PO
李海彬
2018/03/21
1.1K0
Golang语言写Web 应用程序
Go 学习笔记3 - 编写一个Web应用程序
掌握了Go的基础语法后,让我们开始动手实战,尝试写一个 简易的wiki 小应用,它是一个 web 应用项目(网页应用)。
张云飞Vir
2020/03/20
6310
理解Go语言Web编程(上)
断断续续学Go语言很久了,一直没有涉及Web编程方面的东西。因为仅是凭兴趣去学习的,时间有限,每次去学,也只是弄个一知半解。不过这两天下定决心把Go语言Web编程弄懂,就查了大量资料,边学边记博客。希望我的这个学习笔记对其他人同样有帮助,由于只是业余半吊子学习,文中必然存在诸多不当之处,恳请读者留言指出,在此先道一声感谢! 本文只是从原理方面对Go的Web编程进行理解,尤其是详细地解析了net/http包。由于篇幅有限,假设读者已经熟悉Writing Web Applications这篇文章,这里所进行的工
李海彬
2018/03/22
1.3K0
理解Go语言Web编程(上)
golang学习之文件上传
首先是上传页面upload.html: <!doctype html> <html> <head> <meta charset="utf-8"> <title>Upload</title> </hea
用户1141560
2017/12/26
1K0
翻译golang官网文章Writing Web Applications
原文:https://golang.org/doc/articles/wiki/ 应该有人翻译过了, 不过边翻译边学边做, 感觉还不错
NothAmor
2022/06/08
1910
Go语言(十二)web编程
web编程 web编程基础 web的工作方式 http协议介绍 http请求体 http响应体 Web程序开发 基于“net/http”封装的web服务相关的功能 使用简单 func sayhel
alexhuiwang
2020/09/24
1.1K0
Go语言(十二)web编程
理解Go语言Web编程(下)
ListenAndServe函数 前面所有示例程序中,都在main函数中调用了ListenAndServe函数。下面对此函数所做的工作进行分析。该函数的实现为: func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe() } 该函数新建了一个Server对象,然后调用该Server的L
李海彬
2018/03/22
2.2K0
Go 每日一库之 gorilla/mux
gorilla/mux是 gorilla Web 开发工具包中的路由管理库。gorilla Web 开发包是 Go 语言中辅助开发 Web 服务器的工具包。它包括 Web 服务器开发的各个方面,有表单数据处理包gorilla/schema,有 websocket 通信包gorilla/websocket,有各种中间件的包gorilla/handlers,有 session 管理包gorilla/sessions,有安全的 cookie 包gorilla/securecookie。本文先介绍gorilla/mux(下文简称mux),后续文章会依次介绍上面列举的 gorilla 包。
用户7731323
2021/07/23
1.3K0
Go 每日一库之 gorilla/sessions
上一篇文章《Go 每日一库之 securecookie》中,我们介绍了 cookie。同时提到 cookie 有两个缺点,一是数据不宜过大,二是安全问题。session 是服务器端的存储方案,可以存储大量的数据,而且不需要向客户端传输,从而解决了这两个问题。但是 session 需要一个能唯一标识用户的 ID,这个 ID 一般存放在 cookie 中发送到客户端保存,随每次请求一起发送到服务器。cookie 和 session 通常配套使用。
用户7731323
2021/08/20
1.1K0
Go 每日一库之 gorilla/sessions
在Go中使用服务对象模式
NOTE: Most of the code and ideas in this post are things I have been experimenting with. That doesn't mean the ideas and lessons aren't valuable, but it does mean that you shouldn't just blindly follow this pattern. It has its own set of pros and cons that should be considered on a case-by-case basis. That said, the pattern has been working very well for me and using a design to isolate parsing data from application logic is a critical step in building web applications that support multiple formats (HTML and JSON API), as we will explore in a future post.
李海彬
2018/07/26
4540
在Go中使用服务对象模式
Go Web---Web服务器
http 是比 tcp 更高层的协议,它描述了网页服务器如何与客户端浏览器进行通信。Go 提供了 net/http 包,我们马上就来看下。
大忽悠爱学习
2022/08/23
12.3K0
Go Web---Web服务器
上下文变量值(context values)陷阱及在 Go 中如何避免或缓和这些陷阱
在 context.Context 中存储数据,或者说使用上下文变量值(context values)是在 Go 中最有争议的设计模式之一。在上下文中存储值似乎看起来不错,但是应该将什么东西存储为上下文变量值引起了广泛的讨论。
Fireflywang
2022/07/28
1.8K0
Go sql-web
今天把database/sql部分的内容学习了一下,然后写了一个小项目,巩固一下,代码整体不难。
f1sh
2024/08/01
842
Go-模板引擎(一)
在Web开发中,模板引擎是一个非常重要的工具,它可以让我们轻松地生成HTML、XML和其他文本格式的输出。在Go语言中,html/template和text/template包是两个常用的模板引擎。
堕落飞鸟
2023/04/23
5380
【Go Web 篇】Go 语言进行 Web 开发:构建高性能网络应用
随着互联网的快速发展,Web 开发已经成为了软件开发领域中不可或缺的一部分。随之而来的是对于更高性能、更高效的网络应用的需求。在这个领域,Go 语言因其并发性能、简洁的语法以及丰富的标准库而备受关注。本篇博客将深入探讨如何使用 Go 语言进行 Web 开发,构建出高性能的网络应用。
繁依Fanyi
2023/10/12
1.5K0
【Go Web 篇】Go 语言进行 Web 开发:构建高性能网络应用
Go-模板引擎(二)
text/template包是Go语言标准库中提供的另一个模板引擎,它与html/template包的语法类似,但不支持自动转义。
堕落飞鸟
2023/04/23
2390
从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据
本节中我们将介绍如何在现有的 OAuth 2.0 服务器上访问您的数据。对于此示例,我们将使用 GitHub API 并构建一个简单的应用程序,该应用程序将列出登录用户创建的所有存储库。
用户1418987
2023/10/16
2030
从0开始构建一个Oauth2Server服务 <2> 访问 OAuth 服务器中的数据
Golang语言社区--模板的使用
使用Parse package main import ( "html/template" "net/http" ) func SayHello(w http.ResponseWriter, req *http.Request) { name := "dabin" tmpl, _ := template.New("TXT").Parse("大家好,我是{{.}}") tmpl.Execute(w, name) } func main() { http.Hand
李海彬
2018/03/21
7240
相关推荐
Go语言写Web 应用程序
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档