服务计算阅读收获:《Golang web 应用开发》

服务计算阅读收获:《Golang web 应用开发》

ps: 之前以为阅读作业都是自己默默做了就好了,现在才知道写了博客是有加分的o(╥﹏╥)o

概述

本次博客是关于《Golang web 应用开发》的阅读分享,本书在github
共14章,有着32.8k star(我也在其中哈哈),目录结构为

  1. Go环境配置
  2. Go语言基础
  3. Web基础
  4. 表单
  5. 访问数据库
  6. session和数据存储
  7. 文本文件处理
  8. Web服务
  9. 安全与加密
  10. 国际化和本地化
  11. 错误处理,调试和测试
  12. 部署与维护
  13. 如何设计一个Web框架
  14. 扩展Web框架

我原以为它只是一本关于golang web开发的书,结果它居然从头开始讲起,看了一下质量很高,是十分优质的入门tutorial(gotour也是,不知道为什么golang的教程都这么优质)。前面两章我们已有基础略过,后面的章节有些超出我时间精力范围,所以没有阅读到,我主要想分享的是第三第四章的重要部分(主要是顶层部分和与下次作业相关的部分),它们也和我们的下次作业有关。

Web基础

我们在用golang进行web开发之前需要先了解web的工作流程,它的工作流程图如下:
服务计算阅读收获:《Golang web 应用开发》_第1张图片
客户端先请求DNS解析域名,然后访问服务端,等待回复,最后更新页面,这就是WEB的工作简单流程,这实际上是计算机网络的知识。
其中DNS解析的过程常常涉及到多级DNS域名服务器:
服务计算阅读收获:《Golang web 应用开发》_第2张图片
向服务器发出请求也有不同的方法:
最为常见的方法是GET和POST,一个用于获取信息,一个用于提交信息。
Request包代表了请求信息的内容:
服务计算阅读收获:《Golang web 应用开发》_第3张图片
服务器会返回相应的内容Response:
服务计算阅读收获:《Golang web 应用开发》_第4张图片
这就是web的简单基础,我们尝试着用golang来搭建一个简易的WEB服务器,这里我们使用书中的示例代码

package main

import (
	"fmt"
	"net/http"
	"strings"
	"log"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()  //解析参数,默认是不会解析的
	fmt.Println(r.Form)  //这些信息是输出到服务器端的打印信息
	fmt.Println("path", r.URL.Path)
	fmt.Println("scheme", r.URL.Scheme)
	fmt.Println(r.Form["url_long"])
	for k, v := range r.Form {
		fmt.Println("key:", k)
		fmt.Println("val:", strings.Join(v, ""))
	}
	fmt.Fprintf(w, "Hello astaxie!") //这个写入到w的是输出到客户端的
}

func main() {
	http.HandleFunc("/", sayhelloName) //设置访问的路由
	err := http.ListenAndServe(":9090", nil) //设置监听的端口
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

这部分代码实现的功能就是监听本地9090端口,并且根据任何路径和任何请求方法都返回"Hello astaxie!"字符串
服务计算阅读收获:《Golang web 应用开发》_第5张图片

剖析代码

代码实际上只设置了一个访问路由,并为其分配了sayhelloName方法:

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()  //解析参数,默认是不会解析的
	fmt.Println(r.Form)  //这些信息是输出到服务器端的打印信息
	fmt.Println("path", r.URL.Path)
	fmt.Println("scheme", r.URL.Scheme)
	fmt.Println(r.Form["url_long"])
	for k, v := range r.Form {
		fmt.Println("key:", k)
		fmt.Println("val:", strings.Join(v, ""))
	}
	fmt.Fprintf(w, "Hello astaxie!") //这个写入到w的是输出到客户端的
}

该方法会打印reques的各个字段,并且给response写入字符串。

这里涉及到监听端口的部分:

err := http.ListenAndServe(":9090", nil) //设置监听的端口

一台主机有许多端口,每个端口和各自的进程相绑定,端口类似于门牌号,为数据包找到正确的程序宿主,端口的绑定常常用socket(套接字),一个WEB服务器通过套接字来监听端口的大概流程是这样的:
服务计算阅读收获:《Golang web 应用开发》_第6张图片

表单提交

Web服务器通常有两种请求方法:GET和POST。
POST是提交方法,它一般就是通过表单来实现的。
我们先来看看示例代码

package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()       //解析url传递的参数,对于POST则解析响应包的主体(request body)
	//注意:如果没有调用ParseForm方法,下面无法获取表单的数据
	fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息
	fmt.Println("path", r.URL.Path)
	fmt.Println("scheme", r.URL.Scheme)
	fmt.Println(r.Form["url_long"])
	for k, v := range r.Form {
		fmt.Println("key:", k)
		fmt.Println("val:", strings.Join(v, ""))
	}
	fmt.Fprintf(w, "Hello astaxie!") //这个写入到w的是输出到客户端的
}

func login(w http.ResponseWriter, r *http.Request) {
	fmt.Println("method:", r.Method) //获取请求的方法
	if r.Method == "GET" {
		t, _ := template.ParseFiles("login.gtpl")
		log.Println(t.Execute(w, nil))
	} else {
		//请求的是登录数据,那么执行登录的逻辑判断
		r.ParseForm()
		fmt.Println("username:", r.Form["username"])
		fmt.Println("password:", r.Form["password"])
	}
}

func main() {
	http.HandleFunc("/", sayhelloName)       //设置访问的路由
	http.HandleFunc("/login", login)         //设置访问的路由
	err := http.ListenAndServe(":9090", nil) //设置监听的端口
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

需要先准备好一个login.gtpl

<html>
<head>
<title>title>
head>
<body>
<form action="/login" method="post">
	用户名:<input type="text" name="username">
	密码:<input type="password" name="password">
	<input type="submit" value="登录">
form>
body>
html>

效果
服务计算阅读收获:《Golang web 应用开发》_第7张图片
这里加了一个handle函数

func login(w http.ResponseWriter, r *http.Request) {
	fmt.Println("method:", r.Method) //获取请求的方法
	if r.Method == "GET" {
		t, _ := template.ParseFiles("login.gtpl")
		log.Println(t.Execute(w, nil))
	} else {
		//请求的是登录数据,那么执行登录的逻辑判断
		r.PaserForm()
		fmt.Println("username:", r.Form["username"])
		fmt.Println("password:", r.Form["password"])
	}
}

它会根据请求方法的不同执行不同的逻辑
需要注意的是源代码漏了r.PaserForm(),这会导致解析出来的字段全是空的。
在这里插入图片描述
验证表达的输入是否合法我们用正则表达式即可,在这里不赘述了。

处理文件上传

func upload(w http.ResponseWriter, r *http.Request) {
	fmt.Println("method:", r.Method) //获取请求的方法
	if r.Method == "GET" {
		crutime := time.Now().Unix()
		h := md5.New()
		io.WriteString(h, strconv.FormatInt(crutime, 10))
		token := fmt.Sprintf("%x", h.Sum(nil))

		t, _ := template.ParseFiles("upload.gtpl")
		t.Execute(w, token)
	} else {
		r.ParseMultipartForm(32 << 20)
		file, handler, err := r.FormFile("uploadfile")
		if err != nil {
			fmt.Println(err)
			return
		}
		defer file.Close()
		fmt.Fprintf(w, "%v", handler.Header)
		f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)  // 此处假设当前目录下已存在test目录
		if err != nil {
			fmt.Println(err)
			return
		}
		defer f.Close()
		io.Copy(f, file)
	}
}

我们需要提前创建好test文件夹,不然会出现路径错误
服务计算阅读收获:《Golang web 应用开发》_第8张图片
服务计算阅读收获:《Golang web 应用开发》_第9张图片
这段代码的逻辑也比较简单,主要涉及到的就是几个api的调用。

总结

看了这本书的几个章节(其实是个github),感叹道golang的相关教程资源之完善强大,比CSDN高到不知道哪里去了,感谢开源精神。
看了几个章节对golang搭建web有了初步了解了,感觉比以前的node.js好用不少,golang让我看到了未来编程语言的希望,的确如潘老师所讲,有了golang,你还要框架干什么,golang这种简单易用的特性让我很喜欢。

你可能感兴趣的:(技术之路)