Web开发Golang实现Web服务器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web开发Golang实现Web服务器相关的知识,希望对你有一定的参考价值。
(本节内容如下:)
1、简介
- Go是谷歌支持的一种开源编程语言
- 易于学习和入门
- 内置并发性和强大的标准库
- 不断增长的合作伙伴、社区和工具生态系统
相关网站: https://go.dev/ https://golang.google.cn/ https://studygolang.com/dl https://www.runoob.com/go/go-tutorial.html
<font color=blue> Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 <font color=blue> Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。 Golang其高效而又友好的语法,赢得了很多后端开发人员的青睐,最适用于高并发网络编程的语言之一。 Golang(又称Go)是Google公司开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。
- Build fast, reliable, and efficient software at scale
- Go is an open source programming language supported by Google
- Easy to learn and get started with
- Built-in concurrency and a robust standard library
- Growing ecosystem of partners, communities, and tools
2、安装和配置
2.1 下载
https://golang.google.cn/dl/ https://golang.google.cn/dl/go1.19.1.windows-amd64.msi
Go有多种安装方式,你可以选择自己喜欢的。这里我们介绍三种最常见的安装方式:
- Go源码安装:这是一种标准的软件安装方式。对于经常使用Unix类系统的用户,尤其对于开发者来说,从源码安装可以自己定制。
- Go标准包安装:Go提供了方便的安装包,支持Windows、Linux、Mac等系统。这种方式适合快速安装,可根据自己的系统位数下载好相应的安装包,一路next就可以轻松安装了。推荐这种方式
- 第三方工具安装:目前有很多方便的第三方软件包工具,例如Ubuntu的apt-get、Mac的homebrew等。这种安装方式适合那些熟悉相应系统的用户。
这里直接使用Go标准包进行安装。
2.2 安装
直接点击安装包运行即可。 安装完毕之后,打开VsCode,在终端输入命令测试是否安装成功:
go version
2.3 配置
这里在VsCode里进行go语言的相关开发。 然后我们打开 VSCode 的扩展(Ctrl+Shift+P):
- 为了能在国内网络环境下正常的安装go开发工具包,使用go mod 代理来安装go插件:
# 新版改成如下链接
go env -w GO111MODULE=on
go env -w GOPROXY=https://proxy.golang.com.cn,direct
- 问题:go.mod file not found in current directory or any parent directory; see ‘go help modules‘?
go env -w GO111MODULE=auto
2.4 编译
- Go语言目录结构 一个Go语言项目的目录一般包含以下三个子目录: src 目录:放置项目和库的源文件; pkg 目录:放置编译后生成的包/库的归档文件; bin 目录:放置编译后生成的可执行文件。
Go语言是编译型的静态语言(和C语言一样),所以在运行Go语言程序之前,先要将其编译成二进制的可执行文件。可以通过Go语言提供的go build或者go run命令对Go语言程序进行编译:
- go build命令可以将Go语言程序代码编译成二进制的可执行文件,但是需要我们手动运行该二进制文件;
- go run命令则更加方便,它会在编译后直接运行Go语言程序,编译过程中会产生一个临时文件,但不会生成可执行文件,这个特点很适合用来调试程序。
D:\\0607> go build .\\test\\test_go1.go
D:\\0607> .\\test_go1.exe
Hello World, 爱看书的小沐, 2022!
3、语法
3.1 关键词
- Go 代码中会使用到的 25 个关键字或保留字:
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
- Go 语言还有 36 个预定义标识符:
append bool byte cap close complex complex64 complex128 uint16
copy false float32 float64 imag int int8 int16 uint32
int32 int64 iota len make new nil panic uint64
print println real recover string true uint uint8 uintptr
3.2 注释
//单行注释
/*
多行注释
多行注释
*/
3.3 数据类型
在 Go 编程语言中,数据类型用于声明函数和变量。
序号 | 类型 | 描述 |
---|---|---|
1 | 布尔型 | <div align=left>布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。 |
2 | 数字类型 | <div align=left>整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。 |
3 | 字符串类型 | <div align=left>字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。 |
4 | 派生类型 | <div align=left>包括:<br>(a) 指针类型(Pointer)<br>(b) 数组类型<br> (c) 结构化类型(struct)<br>(d) Channel 类型<br>(e) 函数类型(function)<br>(f) 切片类型(slice切片:不定长数组)<br>(g) 接口类型(interface)<br>(h) Map 类型(字典) |
3.4 变量赋值
Go是静态语言,是强类型的,但是Go语言也允许在赋值变量时确定类型。 Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。 声明变量的一般形式是使用 var 关键字:
// 1. 完整的申明并赋值
var a int
a = 1
// 2. 声明变量类型同时赋值
var a int = 1
// 3. 不声明类型,赋值时确定
var a = 1
// 4. 不用 var 关键字申明变量并赋值后确定类型
a := 1
package main
import "fmt"
func main()
fmt.Println("Hello, 爱看书的小沐, 2022!")
fmt.Println("i am a robot!")
var s string = "爱看书的小沐"
fmt.Println(s)
s = "tomcat"
fmt.Println(s)
s2 := "apple"
fmt.Println(s2)
3.5 函数定义
Go用func定义函数,没有默认值参数、没有关键字参数,但是有很多其他特征。
func main()
println(foo(18, "tomcat"))
func foo(age int, name string) (r string)
r = fmt.Sprintf("my name is %s , age %d", name, age)
return
3.6 内置库
-
fmt fmt 包实现了格式化的标准输入输出,这与C语言中的 printf 和 scanf 类似。其中的 fmt.Printf() 和 fmt.Println() 是开发者使用最为频繁的函数。 格式化短语派生于C语言,一些短语(%- 序列)是这样使用:
-
io 这个包提供了原始的 I/O 操作界面。它主要的任务是对 os 包这样的原始的 I/O 进行封装,增加一些其他相关,使其具有抽象功能用在公共的接口上。
-
bufio bufio 包通过对 io 包的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。 在 bufio 各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据,只有当缓冲区没有数据时,才会从数据源获取数据更新缓冲。
-
sort sort 包提供了用于对切片和用户定义的集合进行排序的功能。
-
strconv strconv 包提供了将字符串转换成基本数据类型,或者从基本数据类型转换为字符串的功能。
-
os os 包提供了不依赖平台的操作系统函数接口,设计像 Unix 风格,但错误处理是 go 风格,当 os 包使用时,如果失败后返回错误类型而不是错误数量。
-
sync sync 包实现多线程中锁机制以及其他同步互斥机制。
-
flag flag 包提供命令行参数的规则定义和传入参数解析的功能。绝大部分的命令行程序都需要用到这个包。
-
encoding/json JSON 目前广泛用做网络程序中的通信格式。encoding/json 包提供了对 JSON 的基本支持,比如从一个对象序列化为 JSON 字符串,或者从 JSON 字符串反序列化出一个具体的对象等。
-
html/template 主要实现了 web 开发中生成 html 的 template 的一些函数。
-
net/http net/http 包提供 HTTP 相关服务,主要包括 http 请求、响应和 URL 的解析,以及基本的 http 客户端和扩展的 http 服务。 通过 net/http 包,只需要数行代码,即可实现一个爬虫或者一个 Web 服务器,这在传统语言中是无法想象的。
-
reflect reflect 包实现了运行时反射,允许程序通过抽象类型操作对象。通常用于处理静态类型 interface 的值,并且通过 Typeof 解析出其动态类型信息,通常会返回一个有接口类型 Type 的对象。
-
os/exec os/exec 包提供了执行自定义 linux 命令的相关实现。
-
strings strings 包主要是处理字符串的一些函数集合,包括合并、查找、分割、比较、后缀检查、索引、大小写处理等等。 strings 包与 bytes 包的函数接口功能基本一致。
-
bytes bytes 包提供了对字节切片进行读写操作的一系列函数。字节切片处理的函数比较多,分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等。
-
log log 包主要用于在程序中输出日志。 log 包中提供了三类日志输出接口,Print、Fatal 和 Panic。
4、入门示例
4.1 hello world
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
func main()
fmt.Println("Hello, 爱看书的小沐!")
4.2 goroutine
package main
import (
"fmt"
"time"
)
func running()
var times int
// 构建一个无限循环
for
times++
fmt.Println("时间1: ", times)
// 延时1秒
time.Sleep(time.Second)
func running2()
var times int
// 构建一个无限循环
for
times++
fmt.Println("时间2: ", times)
// 延时1秒
time.Sleep(time.Second)
func main()
// 并发执行程序
go running()
go running2()
// 接受命令行输入, 不做任何事情
var input string
fmt.Scanln(&input)
4.3 sqlite3
- 安装sqlite3插件如下:
go get github.com/mattn/go-sqlite3
<font color=red>问题:cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in %PATH%</font> 答:安装gcc即可。
- 测试代码如下:
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/mattn/go-sqlite3"
)
const (
dbDriverName = "sqlite3"
dbName = "./Instruct.db3"
)
type user struct
Username string
Age int
Job string
Hobby string
func main()
db, err := sql.Open(dbDriverName, dbName)
if checkErr(err)
return
rows, err := db.Query("SELECT ID, 动作ID, 触发点ID FROM 触发映射表")
if err != nil
panic(err)
defer rows.Close()
for rows.Next()
var uid int
var aid int
var tname string
err = rows.Scan(&uid, &aid, &tname)
if err != nil
panic(err)
fmt.Println(uid, aid, tname)
func checkErr(e error) bool
if e != nil
log.Fatal(e)
return true
return false
- 运行结果如下:
4.4 zip
package main
import (
"archive/zip"
"bytes"
"fmt"
"os"
)
func main()
// 创建一个缓冲区用来保存压缩文件内容
buf := new(bytes.Buffer)
// 创建一个压缩文档
w := zip.NewWriter(buf)
// 将文件加入压缩文档
var files = []struct
Name, Body string
"Golang.txt", "爱看书的小沐!",
for _, file := range files
f, err := w.Create(file.Name)
if err != nil
fmt.Println(err)
_, err = f.Write([]byte(file.Body))
if err != nil
fmt.Println(err)
// 关闭压缩文档
err := w.Close()
if err != nil
fmt.Println(err)
// 将压缩文档内容写入文件
f, err := os.OpenFile("file.zip", os.O_CREATE|os.O_WRONLY, 0666)
if err != nil
fmt.Println(err)
buf.WriteTo(f)
5、web 服务器(net/http)
5.1 net/http
Go语言里面提供了一个完善的 net/http 包,通过 net/http 包我们可以很方便的搭建一个可以运行的 Web 服务器。同时使用 net/http 包能很简单地对 Web 的路由,静态文件,模版,cookie 等数据进行设置和操作。
- 第一个测试例子:
package main
import (
"fmt"
"log"
"net/http"
)
func main()
http.HandleFunc("/", index) // index 为向 url发送请求时,调用的函数
log.Fatal(http.ListenAndServe("localhost:8000", nil))
func index(res http.ResponseWriter, req *http.Request)
fmt.Fprintf(res, "Hello world, 爱看书的小沐的家!")
- 浏览器访问,运行结果如下:
- 第二个测试例子:
package main
import (
"io"
"log"
"net/http"
)
func main()
// Hello world, the web server
helloHandler := func(w http.ResponseWriter, req *http.Request)
io.WriteString(w, "Hello, world,爱看书的小沐的家!\\n")
http.HandleFunc("/hello", helloHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
5.2 net/http + index.html
- test.go:
package main
import (
"io/ioutil"
"log"
"net/http"
)
func main()
http.HandleFunc("/", index)
http.HandleFunc("/index", index)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
func index(w http.ResponseWriter, r *http.Request)
content, _ := ioutil.ReadFile("./index.html")
w.Write(content)
- index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>爱看书的小沐</title>
</head>
<body>
这是爱看书的小沐的web服务器
</body>
</html>
- 浏览器访问,运行结果:
5.2 net/http + HttpRouter
HttpRouter包为常用的HTTP方法提供了GET(),POST(),方法都提供了定义。 同时它为URL提供了两种匹配模式: /user/:pac 精准匹配 /user/pac /user/*pac 匹配所有模式 /user/hello
- 安装go插件如下:
go get github.com/julienschmidt/httprouter
- 测试代码如下:
package main
import (
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
fmt.Fprint(w, "Welcome, 爱看书的小沐!\\n")
func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params)
fmt.Fprintf(w, "hello, %s!\\n", ps.ByName("name"))
func Test(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
w.Write([]byte("Test, httprouter!"))
func main()
router := httprouter.New()
router.GET("/", Index)
router.GET("/hello/:name", Hello)
router.GET("/test", Hello)
log.Fatal(http.ListenAndServe(":8000", router))
- 浏览器访问,运行结果:
5.3 net/http + FileServer
package main
import (
"log"
"net/http"
)
func main()
// Simple static webserver:
log.Fatal(http.ListenAndServe(":8000", http.FileServer(http.Dir("D:/3D XML Player/win_b64/resources"))))
5.4 net/http + NewServeMux
package main
import (
"fmt"
"net/http"
)
func newPeopleHandler() http.Handler
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request)
fmt.Fprintln(w, "This is the people handler.")
)
// 设置多个处理器函数
func handler1(w http.ResponseWriter, r *http.Request)
fmt.Fprintf(w, "1 >> apple")
func handler2(w http.ResponseWriter, r *http.Request)
fmt.Fprintf(w, "1 >> pear")
func handler3(w http.ResponseWriter, r *http.Request)
fmt.Fprintf(w, "1 >> banana")
func main()
mux := http.NewServeMux()
// Create sample handler to returns 404
mux.Handle("/resources", http.NotFoundHandler())
// Create sample handler that returns 200
mux.Handle("/resources/people/", newPeopleHandler())
mux.HandleFunc("/h1", handler1)
mux.HandleFunc("/h2", handler2)
mux.HandleFunc("/h3", handler3)
//log.Fatal(http.ListenAndServe(":8000", mux))
// 设置服务器
server := &http.Server
Addr: "127.0.0.1:8000",
Handler: mux,
// 设置服务器监听请求端口
server.ListenAndServe()
5.5 net/http + ssl
- Golang Web SSL证书 创建生成 pem x.509
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"os"
"time"
)
func main()
max := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, _ := rand.Int(rand.Reader, max)
// 定义:引用IETF的安全领域的公钥基础实施(PKIX)工作组的标准实例化内容
subject := pkix.Name
Organization: []string"WWW.xiaomu.COM",
OrganizationalUnit: []string"ITs",
CommonName: "xiaomu.COM Web",
// 设置 SSL证书的属性用途
certificate509 := x509.Certificate
SerialNumber: serialNumber,
Subject: subject,
NotBefore: time.Now(),
NotAfter: time.Now().Add(100 * 24 * time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsagex509.ExtKeyUsageServerAuth,
IPAddresses: []net.IPnet.ParseIP("127.0.0.1"),
// 生成指定位数密匙
pk, _ := rsa.GenerateKey(rand.Reader, 1024)
// 生成 SSL公匙
derBytes, _ := x509.CreateCertificate(rand.Reader, &certificate509, &certificate509, &pk.PublicKey, pk)
certOut, _ := os.Create("cert.pem")
pem.Encode(certOut, &pem.BlockType: "CERTIFICATE", Bytes: derBytes)
certOut.Close()
// 生成 SSL私匙
keyOut, _ := os.Create("key.pem")
pem.Encode(keyOut, &pem.BlockType: "RAS PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk))
keyOut.Close()
- https服务器测试代码如下:
package main
import (
"io"
"log"
"net/http"
)
func main()
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request)
io.WriteString(w, "Hello, 爱看书的小沐, TLS!\\n")
)
// One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.
log.Printf("About to listen on 8443. Go to https://127.0.0.1:8443/")
err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", nil)
log.Fatal(err)
- 浏览器测试如下:
5.3 net/http + client
- 客户端例子1:
package main
import (
"fmt"
"net/http"
)
func main()
resp, err := http.Get("http://baidu.com/")
fmt.Println(resp, err)
- 客户端例子2:
package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main()
res, err := http.Get("http://www.baidu.com/robots.txt")
if err != nil
log.Fatal(err)
body, err := io.ReadAll(res.Body)
res.Body.Close()
if res.StatusCode > 299
log.Fatalf("Response failed with status code: %d and\\nbody: %s\\n", res.StatusCode, body)
if err != nil
log.Fatal(err)
fmt.Printf("%s", body)
- 客户端例子3:
package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main()
req, err := http.NewRequest("GET", "https://icanhazdadjoke.com", nil)
if err != nil
log.Fatalln(err)
req.Header.Set("Accept", "application/json")
client := &http.Client
resp, err := client.Do(req)
if err != nil
log.Fatalln(err)
defer resp.Body.Close()
// b, err := io.ReadAll(resp.Body)
// // b, err := ioutil.ReadAll(resp.Body) Go.1.15 and earlier
// if err != nil
// log.Fatalln(err)
//
b, err := httputil.DumpResponse(resp, true)
if err != nil
log.Fatalln(err)
fmt.Println(string(b))
6、web 框架
https://golang.google.cn/solutions/webdev https://github.com/speedwheel/awesome-go-web-frameworks/blob/master/README.md#popularity
6.1 echo
$ mkdir myapp
$ cd myapp
$ go mod init myapp
$ go get github.com/labstack/echo/v4
安装过程如下:
- 入门例子:
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main()
e := echo.New()
e.GET("/", func(c echo.Context) error
return c.String(http.StatusOK, "Hello, 爱看书的小沐!")
)
e.Logger.Fatal(e.Start(":1323"))
- 不同类型的路由:
e.POST("/users", saveUser)
e.GET("/users/:id", getUser)
e.PUT("/users/:id", updateUser)
e.DELETE("/users/:id", deleteUser)
// e.GET("/users/:id", getUser)
func getUser(c echo.Context) error
// User ID from path `users/:id`
id := c.Param("id")
return c.String(http.StatusOK, id)
//e.GET("/show", show)
func show(c echo.Context) error
// Get team and member from the query string
team := c.QueryParam("team")
member := c.QueryParam("member")
return c.String(http.StatusOK, "team:" + team + ", member:" + member)
// e.POST("/save", save)
func save(c echo.Context) error
// Get name and email
name := c.FormValue("name")
email := c.FormValue("email")
return c.String(http.StatusOK, "name:" + name + ", email:" + email)
6.2 beego
https://github.com/beego/beego https://beego.vip/
库安装命令如下:
mkdir hello
cd hello
go mod init
go get github.com/beego/beego/v2@v2.0.0
测试代码如下:
package main
import "github.com/beego/beego/v2/server/web"
func main()
web.Run()
package main
import (
"github.com/beego/beego/v2/server/web"
)
type MainController struct
web.Controller
func (this *MainController) Get()
this.Ctx.WriteString("hello world, beego, 爱看书的小沐!")
func main()
web.Router("/", &MainController)
web.Run()
结语
如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;
╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地
//(ㄒoㄒ)//,就在评论处留言,作者继续改进;
o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;
(✿◡‿◡)
感谢各位大佬童鞋们的支持!
( ´ ▽´ )ノ ( ´ ▽´)っ!!!
以上是关于Web开发Golang实现Web服务器的主要内容,如果未能解决你的问题,请参考以下文章