從0開始Go語言,用Golang搭建網站

實踐是最好的學習方式

零基礎經過開發Web服務學習Go語言javascript

本文適合有必定編程基礎,可是沒有Go語言基礎的同窗。css

也就是俗稱的「騙你」學Go語言系列。html

這是一個適合閱讀的系列,我但願您可以在車上、廁所、餐廳都閱讀它,涉及代碼的部分也是精簡而實用的。前端

學習須要動機

Go語言能幹什麼?爲何要學習Go語言?java

本系列文章,將會以編程開發中需求最大、應用最廣的Web開發爲例,一步一步的學習Go語言。當看完本系列,您可以清晰的瞭解Go語言Web開發的基本原理,您會驚歎於Go語言的簡潔、高效和新鮮。linux

結果反饋才能讓你記住

《刻意練習》一書中說,學習須要及時反饋結果,才能提升學習體驗。程序員

本系列文章的每一節,都會包含一段可運行的有效代碼,跟着內容一步一步操做,你能夠在你本身的計算機上體驗每一句代碼的做用。golang

不要學習不須要的東西

文章圍繞範例爲核心,介紹知識點。文中不羅列語法和關鍵字,當您還不知道它們用來幹什麼時,反而會干擾您的注意力。web

但願您在閱讀本系列文章後,對Go語言產生更多的學習慾望,成爲一名合格的Gophershell

Gopher:原譯是囊地鼠,也就是Go語言Logo的那個小可愛;這裏特指Go程序員給本身的暱稱。

如何10分鐘搭建Go開發環境

1.下載Go語言安裝文件

訪問Go語言官方網站下載頁面:

golang.org/dl

能夠看到官網提供了Microsoft Windows、Apple MacOS、Linux和Source下載。

直接下載對應操做系統的安裝包。

2.和其餘軟件同樣,根據提示安裝

3.配置環境變量

在正式使用Go編寫代碼以前,還有一個重要的「環境變量」須要配置:「$GOPATH」

GOPATH環境變量指定工做區的位置。若是沒有設置GOPATH,則假定在Unix系統上爲$HOME/go,在Windows上爲 %USERPROFILE%\go。若是要將自定義位置用做工做空間,能夠設置GOPATH環境變量。

GOPATH環境變量是用於設置Go編譯能夠執行文件、包源碼以及依賴包所必要的工做目錄路徑,Go1.11後,新的木塊管理雖然能夠再也不依賴 $GOPATH/src,可是依然須要使用 $GOPATH/pkg 路徑來保存依賴包。

首先,建立好一個目錄用做GOPATH目錄

而後設置環境變量 GOPATH:

Linux & MacOS:


導入環境變量

$ export GOPATH=$YOUR_PATH/go

保存環境變量

$ source ~/.bash_profile

Windows:


控制面板->系統->高級系統設置->高級->環境變量設置

GOPATH設置好後,它是一個空目錄,當在開發工做中執行go get、go install命令後,GOPATH所指定的目錄會生成3個子目錄:

  • bin:存放 go install 編譯的可執行二進制文件
  • pkg:存放 go install 編譯後的包文件,就會存放在這裏
  • src:存放 go get 命令下載的源碼包文件

4.檢查環境

打開命令行工具,運行

$ go env

若是你看到相似這樣的結果,說明Go語言環境安裝完成.

GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/zeta/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/zeta/workspace/go"
GOPROXY="https://goproxy.io"
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/7v/omg2000000000000019/T/go-build760324613=/tmp/go-build -gno-record-gcc-switches -fno-common"
複製代碼

5.選擇一款趁手的編輯器或IDE

如今不少通用的編輯器或IDE都支持Go語言好比

Go語言專用的IDE有

專用的IDE不管是配置和使用都比通用編輯器/IDE的簡單許多,可是我仍是推薦你們使用通用編輯器/IDE,由於在開發過程當中確定會須要編寫一些其餘語言的程序或腳本,專用IDE在其餘語言編寫方面較弱,來回切換不一樣的編輯器/IDE窗口會很低效。

另外,專用IDE提供不少高效的工具,在編譯、調試方面都很方便,可是學習階段,建議你們手動執行命令編譯、調試,有利於掌握Go語言。

四行代碼的Hello World!所能表達出來的核心

命令行代碼僅適用於Linux和MacOS系統,Windows根聽說明在視窗下操做便可。

1.建立項目

建立一個文件夾,進入該文件夾

$ mkdir gowebserver && cd gowebserver

新建一個文件 main.go

$ touch main.go

2. 用編輯器打開文件,並輸入如下代碼:

package main

import "fmt"

func main() {
    fmt.Println("Hello, 世界")
}
複製代碼

3.打開命令行終端,輸入如下命令

$ go run main.go

看到終端會輸出:

Hello, 世界

第一個Go代碼就完成了

這是一個很簡單的Hello World,可是包含了Go語言編程的許多核心元素,接下來就詳細講解。

解讀知識點: 包 與 函數

package申明包 & import導入包

Go程序是由包構成的。

代碼的第一行, 申明程序本身的包,用 package 關鍵字。package關鍵字必須是第一行出現的代碼。

範例代碼中,申明的本包名 main

在代碼中第二行, 導入「fmt」包, 使用 import 關鍵字。默認狀況下,導入包的包名與導入路徑的最後一個元素一致,例如 import "math/rand",在代碼中使用這個包時,直接使用rand,例如 rand.New()

導入包的寫法能夠多行,也能夠「分組」, 例如:

import "fmt"
import "math/rand"
複製代碼

或者 分組

import (
    "fmt"
    "math/rand"
)
複製代碼

fmt包是Go語言內建的包,做用是輸出打印。

func關鍵字:定義函數

func是function的縮寫, 在Go語言中是定義函數的關鍵字。

func定義函數的格式爲:

func 函數名(參數1 類型,參數2 類型){
    函數體
}
複製代碼

本例中定義了一個main函數。main函數沒有參數。 而後在main函數體裏調用fmt包的Println函數,在控制檯輸出字符串 「Hello, 世界」

全部Go語言的程序的入口都是main包下的main函數 main.main(),因此每個可執行的Go程序都應該有一個main包和一個main函數

咱們已經介紹了九牛一毛中的一毛,接下來正式經過搭建一個簡單的Web服務學習Go語言

0依賴,建立一個Web服務

先從代碼開始

打開以前建立好的main.go文件,修改代碼以下:

package main

import (
    "fmt"
    "net/http"
)

func myWeb(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "這是一個開始")
}

func main() {
    http.HandleFunc("/", myWeb)

    fmt.Println("服務器即將開啓,訪問地址 http://localhost:8080")

    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Println("服務器開啓錯誤: ", err)
    }
}
複製代碼

保存文件,而後在命令行工具下輸入命令,運行程序

$ go run main.go

這時候,你會看到用 fmt.Println打印出來的提示,在瀏覽器中訪問 http://localhost:8080你將訪問到一個頁面,顯示 "這是一個開始"

解讀

咱們從程序運行的順序去了解它的工做流程

首先,定義package main,而後導入包。

這裏,導入了一個新的包 net/http,這個包是官方的,實現http客戶端和服務端的各類功能。Go語言開發Web服務的全部功能就是基於這個包(其餘第三方的Go語言Web框架也都基於這個包,沒有例外)

先看main函數裏發生了什麼

第一句,匹配路由和處理函數

http.HandleFunc("/", myWeb)

調用http包的HandleFunc方法,匹配一個路由到一個處理函數myWeb

這句代碼的意思是,當經過訪問地址 http://localhost/ 時,就等同於調用了 myWeb 函數。

第二句,用fmt在控制檯打印一句話,純屬提示。

第三句,開啓服務而且監聽端口

err := http.ListenAndServe(":8080", nil)
複製代碼

在這句,調用了http包中的ListenAndServe函數,該函數有兩個參數,第一個是指定監聽的端口號,第二個是指定處理請求的handler,一般這個參數填nil,表示使用默認的ServeMux做爲handler。

什麼是nil?

nil就是其餘語言裏的null

什麼是handler?什麼是ServeMux? ServeMux就是一個HTTP請求多路由複用器。它將每一個傳入請求的URL與已註冊模式的列表進行匹配,並調用與URL最匹配的模式的處理程序。 很熟悉吧?還記得前面的http.HandleFunc嗎?他就是給http包中默認的ServeMux(DefaultServeMux)添加URL與處理函數匹配。 一般都是使用http包中的默認ServeMux,因此在http.ListenAndServe函數的第二個參數提供nil就能夠了

ListenAndServe函數會一直監聽,除非強制退出或者出現錯誤。

若是這句開啓監聽出現錯誤,函數會退出監聽並會返回一個error類型的對象,所以用err變量接收返回對象。緊接着,判斷err是否爲空,打印出錯誤內容,程序結束。


這裏有兩個Go語言知識點

1.定義變量

Go語言是靜態語言,須要定義變量,定義變量用關鍵字var

var   str   string = "my string"
//^ ^ ^
//關鍵字 變量名 類型
複製代碼

Go還提了一種簡單的變量定義方式:=自動根據賦值的對象定義變量類型,用起來很像腳本語言:

str := "my string"
複製代碼

2.錯誤處理

if err != nil{
    //處理....
}
複製代碼

在Go語言中,這是很常見的錯誤處理操做,另外一種panic異常,官方建議不要使用或儘可能少用,暫不作介紹,先從err開始。

Go語言中規定,若是函數可能出現錯誤,應該返回一個error對象,這個對象至少包含一個Error()方法錯誤信息。

所以,在Go中,是看不到try/catch語句的,函數使用error傳遞錯誤,用if語句判斷錯誤對象而且處理錯誤。


3. if 語句

與大多數語言使用方式同樣,惟一的區別是,表達式不須要()包起來。

另外,Go語言中的if能夠嵌入一個表達式,用;號隔開,例如範例中的代碼能夠改成:

if err := http.ListenAndServe(":8080", nil); err != nil {
    fmt.Println("服務器開啓錯誤: ", err)
}
複製代碼

err這個變量的生命週期只在if塊中有效。

請求處理 myWeb函數

main函數中,用http.HandleFunc將 myWeb與路由/匹配在一塊兒。

HandleFunc函數定義了兩個參數w,r,參數類型分別是http.ResponseWriter*http.Requestw是響應留寫入器,r是請求對象的指針。

響應流寫入器 w: 用來寫入http響應數據

請求對象 * r: 包含了http請求全部信息,注意,這裏使用了指針,在定義參數時用*標記類型,說明這個參數須要的是這個類型的對象的指針

當有請求路徑/,請求對象和響應流寫入器被傳遞給myWeb函數,並由myWeb函數負責處理此次請求。

Go語言中紅的指針: 在Go語言中 除了map、slice、chan 其餘函數傳參都是值傳遞,因此,若是須要達到引用傳遞的效果,經過傳遞對象的指針實現。在Go語言中,取對象的指針用&,取值用*,例如:

mystring := "hi"
//取指針
mypointer := &mystring
//取值
mystring2 := *mypointer

fmt.Println(mystring,mypointer,mystring2)
複製代碼

把這些代碼放在main函數裏,$ go run main.go運行看看

myWeb函數體

fmt.Fprintf(w, "這是一個開始")
複製代碼

再一次遇到老熟人fmt,此次使用他的Fprintf函數將字符串「這是一個開始」,寫入到w響應流寫入器對象。w響應流寫入器裏寫入的內容最後會被Response輸出到用戶瀏覽器的頁面上。

總結一下,從編碼到運行,你和它都幹了些什麼:

  1. 定義一個函數myWeb,接收參數 響應流寫入器和請求對象兩個參數
  2. 在main函數中,在默認的ServeMux中將路由/與myWeb綁定
  3. 運行默認的ServeMux監聽本地8080端口
  4. 訪問本地8080端口 / 路由
  5. http將請求對象和響應寫入器都傳遞給myWeb處理
  6. myWeb向響應流中寫入一句話,結束此次請求。

雖然代碼不多不多,可是這就是一個最基本的Go語言Web服務程序了。

Web互動第一步,Go http 得到請求參數

仍是先從代碼開始

打開main.go文件,修改myWeb函數,以下:

func myWeb(w http.ResponseWriter, r *http.Request) {

    r.ParseForm() //它還將請求主體解析爲表單,得到POST Form表單數據,必須先調用這個函數

    for k, v := range r.URL.Query() {
        fmt.Println("key:", k, ", value:", v[0])
    }

    for k, v := range r.PostForm {
        fmt.Println("key:", k, ", value:", v[0])
    }

    fmt.Fprintln(w, "這是一個開始")
}
複製代碼

運行程序

$ go run main.go

而後用任何工具(推薦Postman)提交一個POST請求,而且帶上URL參數,或者在命令行中用cURL提交

curl --request POST \
  --url 'http://localhost:8080/?name=zeta' \
  --header 'cache-control: no-cache' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data description=hello
複製代碼

頁面和終端命令行工具會答應出如下內容:

key: name , value: zeta
key: description , value: hello
複製代碼

解讀

http請求的全部內容,都保存在http.Request對象中,也就是myWeb得到的參數 r

首先,調用r.ParseForm(),做用是填充數據到 r.Formr.PostForm

接下來,分別循環獲取遍歷打印出 r.URL.Query() 函數返回的值 和 r.PostForm 值裏的每個參數。

r.URL.Query()r.PostForm 分別是URL參數對象和表單參數對象 ,它們都是鍵值對值,鍵的類型是字符串string,值的類型是string數組。

在http協議中,不管URL和表單,相同名稱的參數會組成數組。

循環遍歷:for...range

Go語言的循環只有for關鍵字,如下是Go中4種for循環

//無限循環,阻塞線程,用不停息,慎用!
for{

}

//條件循環,若是a<b,循環,不然,退出循環
for a < b{

}

//表達式循環,設i爲0,i小於10時循環,每輪循環後i增長1
for i:=0; i<10; i++{

}

//for...range 遍歷objs,objs必須是map、slice、chan類型
for k, v := range objs{

}

複製代碼

前3種,循環你能夠看做條件循環的變體(無限循環就是無條件的循環)。

本例種用到的是 for...range 循環,遍歷可遍歷對象,而且每輪循環都會將鍵和值分別賦值給變量 kv


咱們頁面仍是隻是輸出一句「這是一個開始」。咱們須要一個能夠見人的頁面,這樣能夠不行

你也許也想到了,是否是能夠在輸出時,硬編碼HTML字符串?固然能夠,可是Go http包提供了更好的方式,HTML模版。

接下來,咱們就用HTML模版作一個真正的頁面出來

動態響應數據給訪客,Go http HTML模版+數據綁定

讀取HTML模版文件,用數據替換掉對應的標籤,生成完整的HTML字符串,響應給瀏覽器,這是全部Web開發框架的常規操做。Go也是這麼幹的。

Go html包提供了這樣的功能:

"html/template"

從代碼開始

main函數不變,增長導入html/template包,而後修改myWeb函數,以下:

import (
    "fmt"
    "net/http"
    "text/template" //導入模版包
)

func myWeb(w http.ResponseWriter, r *http.Request) {

    t := template.New("index")

    t.Parse("<div id='templateTextDiv'>Hi,{{.name}},{{.someStr}}</div>")

    data := map[string]string{
        "name":    "zeta",
        "someStr": "這是一個開始",
    }

    t.Execute(w, data)

    // fmt.Fprintln(w, "這是一個開始")
}
複製代碼

在命令行中運行 $ go run main.go ,訪問 http://localhost:8080

看,<div id='templateTextDiv'>Hi,{{.name}},{{.someStr}}</div> 中的{{.name}}{{.someStr}} 被替換成了 zeta這是一個開始。而且,再也不使用fmt.Fprintln函數輸出數據到Response了

可是...這仍是在代碼裏硬編碼HTML字符串啊...

彆着急,template包能夠解析文件,繼續修改代碼:

  1. 根目錄下建立一個子目錄存放模版文件 templates, 而後進入目錄建立一個文件 index.html,並寫入一些HTML代碼 (我不是個好前端)
<html>
<head></head>
<body>
    <div>Hello {{.name}}</div>
    <div>{{.someStr}}</div>
</body>
</html>

複製代碼
  1. 修改myWeb函數
func myWeb(w http.ResponseWriter, r *http.Request) {

    //t := template.New("index")
    //t.Parse("<div>Hi,{{.name}},{{.someStr}}<div>")
    //將上兩句註釋掉,用下面一句
    t, _ := template.ParseFiles("./templates/index.html")

    data := map[string]string{
        "name":    "zeta",
        "someStr": "這是一個開始",
    }

    t.Execute(w, data)

    // fmt.Fprintln(w, "這是一個開始")
}
複製代碼

在運行一下看看,頁面按照HTML文件的內容輸出了,而且{{.name}}和{{.someStr}}也替換了,對吧?

解讀

能夠看到,template包的核心功能就是將HTML字符串解析暫存起來,而後調用Execute的時候,用數據替換掉HTML字符串中的{{}}裏面的內容

在第一個方式中 t:=template.New("index") 初始化一個template對象變量,而後用調用t.Parse函數解析字符串模版。

而後,建立一個map對象,渲染的時候會用到。

最後,調用t.Execute函數,不只用數據渲染模版,還替代了fmt.Fprintln函數的工做,將輸出到Response數據流寫入器中。

第二個方式中,直接調用 template包的ParseFiles函數,直接解析相對路徑下的index.html文件並建立對象變量。

知識點

本節出現了兩個新東西 map類型 和 賦值給「_

map類型

map類型: 字典類型(鍵值對),以前的獲取請求參數章節中出現的 url/values類型其實就是從map類型中擴展出來的

map的初始化可使用make

var data = make(map[string]string)
data = map[string]string{}

複製代碼

make是內置函數,只能用來初始化 map、slice 和 chan,而且make函數和另外一個內置函數new不一樣點在於,它返回的並非指針,而只是一個類型。

map賦值於其餘語言的字典對象相同,取值有兩種方式,請看下面的代碼:

data["name"]="zeta" //賦值

name := data["name"] //方式1.普通取值

name,ok := data["name"] //方式2.若是不存在name鍵,ok爲false

複製代碼

代碼中的變量ok,能夠用來判斷這一項是否設置過,取值時若是項不存在,是不會異常的,取出來的值爲該類型的零值,好比 int類型的值,不存在的項就爲0;string類型的值不存在就爲空字符串,因此經過值是否爲0值是不能判斷該項是否設置過的。 ok,會得到true 或者 false,判斷該項是否設置過,true爲存在,false爲不存在於map中。

Go中的map還有幾個特色須要瞭解:

  1. map的項的順序是不固定的,每次遍歷排列的順序都是不一樣的,因此不能用順序判斷內容
  2. map能夠用for...range 遍歷
  3. map在函數參數中是引用傳遞(Go語言中,只有map、slice、chan是引用傳遞,其餘都是值傳遞)

賦值給 「_」

Go有一個特色,變量定義後若是沒使用,會報錯,沒法編譯。通常狀況下沒什麼問題,可是極少狀況下,咱們調用函數,可是並不須要使用返回值,可是不使用,又沒法編譯,怎麼辦?

"_" 就是用來解決這個問題的,_用來丟棄函數的返回值。好比本例中,template.ParseFiles("./templates/index.html") 除了返回模版對象外,還會返回一個error對象,可是這樣簡單的例子,出錯的可能性極小,因此我不想處理error了,將error返回值用「_」丟棄掉。

注意注意注意:在實際項目中,請不要丟棄error,任何意外都是可能出現的,丟棄error會致使當出現罕見的意外狀況時,很是難於Debug。全部的error都應該要處理,至少寫入到日誌或打印到控制檯。(切記,不要丟棄 error ,不少Gopher們在這個問題上有大把的血淚史)

OK,到目前爲止,用Go語言搭建一個簡單的網頁的核心部分就完成了。

等等 .js、.css、圖片怎麼辦?

對。例子裏的模版全是HTML代碼,一個漂亮的網頁還必須用到圖片、js腳本和css樣式文件,但是...和PHP不一樣,請求路徑是經過HandleFunc匹配處處理函數的,難道要把js、css和圖片都經過函數輸出後,再用HandleFunc和URL路徑匹配?

處理好js、css和圖片,才能作漂亮的網頁,Go http靜態文件的處理辦法

以在index.html文件裏引用一個index.js文件爲例。

從代碼開始

func main() {
     http.HandleFunc("/", myWeb)

     //指定相對路徑./static 爲文件服務路徑
     staticHandle := http.FileServer(http.Dir("./static"))
     //將/js/路徑下的請求匹配到 ./static/js/下
     http.Handle("/js/", staticHandle)

     fmt.Println("服務器即將開啓,訪問地址 http://localhost:8080")
     err := http.ListenAndServe(":8080", nil)
     if err != nil {
          fmt.Println("服務器開啓錯誤: ", err)
     }
}
複製代碼

在項目的根目錄下建立static目錄,進入static目錄,建立js目錄,而後在js目錄裏建立一個index.js文件。

alert("Javascript running...");
複製代碼

打開以前的index.html文件,在後面加上 <script src="/js/index.js"></script>

運行 $ go run main.go,訪問 http://localhost:8080,頁面會彈出提示框。

解讀

頁面在瀏覽器中運行時,當運行到<script src="/js/index.js"></script>瀏覽器會請求 /js/index.js這個路徑

程序檢查到第一層路由匹配/js/,因而用文件服務處理此次請求,匹配到程序運行的路徑下相對路徑./static/js

匹配的設置是 main.go文件中這兩句

//指定相對路徑./static 爲文件服務路徑
     staticHandle := http.FileServer(http.Dir("./static"))
     //將/js/路徑下的請求匹配到 ./static/js/下
     http.Handle("/js/", staticHandle)
複製代碼

也能夠寫成一句,更容易理解

//瀏覽器訪問/js/ 將會以靜態文件形式訪問目錄 ./static/js
http.Handle("/js/", http.FileServer(http.Dir("./static")))
複製代碼

很簡單...可是,可能仍是不知足需求,由於, 若是

http.Handle("/js/", http.FileServer(http.Dir("./static"))) 對應到 ./static/js

http.Handle("/css/", http.FileServer(http.Dir("./static"))) 對應到 ./static/css

http.Handle("/img/", http.FileServer(http.Dir("./static"))) 對應到 ./static/img

http.Handle("/upload/", http.FileServer(http.Dir("./static"))) 對應到 ./static/upload

這樣全部請求的路徑都必須匹配一個static目錄下的子目錄。

若是,我就想訪問static目錄下的文件,或者,js、css、img、upload目錄就在項目根目錄下怎麼辦?

http包下,還提供了一個函數 http.StripPrefix 剝開前綴,以下:

//http.Handle("/js/", http.FileServer(http.Dir("./static")))
    //加上http.StripPrefix 改成 :
    http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./static"))))
複製代碼

這樣,瀏覽器中訪問/js/時,直接對應到./static目錄下,不須要再加一個/js/子目錄。

因此,若是須要再根目錄添加多個靜態目錄,而且和URL的路徑匹配,能夠這樣:

http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./js")))) 對應到 ./js

http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./css")))) 對應到 ./css

http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("./img")))) 對應到 ./img

http.Handle("/upload/", http.StripPrefix("/upload/", http.FileServer(http.Dir("./upload")))) 對應到 ./upload

到這裏,一個從流程上完整的Web服務程序就介紹完了。

整理一下,一個Go語言的Web程序基本的流程:

  1. 定義請求處理函數
  2. 用http包的HandleFunc匹配處理函數和路由
  3. ListenAndServe開啓監聽

當有http請求時:

  1. http請求到監聽的的端口
  2. 根據路由將請求對象和響應寫入器傳遞給匹配的處理函數
  3. 處理函數通過一番操做後,將數據寫入到響應寫入器
  4. 響應給請求的瀏覽器

最後編譯程序

以前調試都使用的是 go run 命令運行程序。

您會發現,每次運行go run都會從新編譯源碼,如何將程序運行在沒有Go環境的計算機上?

使用 go build 命令,它會編譯源碼,生成可執行的二進制文件。

最簡單的 go build 命令什麼參數都不用加,它會自動查找目錄下的main包下的main()函數,而後依次查找依賴包編譯成一個可執行文件。

其餘依賴文件的相對路徑須要和編譯成功後的可執行文件一致,例如範例中的templates文件夾和static文件夾。

默認狀況下,go build會編譯爲和開發操做系統對應的可執行文件,若是要編譯其餘操做系統的可執行文件,須要用到交叉編譯。

例如將Linux和MacOSX系統編譯到windows

GOOS=windows GOARCH=amd64 go build

在Windows上須要使用SET命令, 例如在Windows上編譯到Linux系統

SET GOOS=linux
SET GOARCH=amd64
go build main.go
複製代碼

結語,學到了什麼?還要學什麼?

學到了什麼?

  1. 快速簡單搭建Go開發環境
  2. 導入包、申明包
  3. func 定義函數
  4. 變量的申明方法
  5. Go語言的異常處理
  6. for循環
  7. map類型
  8. 用http包,編寫一個網站程序

本系列內容不多,很簡潔,但願您能對Go多一點點了解,對Go多增長一點點興趣。

沒有涉及的其餘知識

還有不少內容成爲一個合格的Gopher必需要了解的知識

  1. struct 結構體
  2. 給struct定義方法
  3. interface 接口定義和實現
  4. chan類型
  5. slice類型
  6. goroutine
  7. panic處理

之後的文章中會涉及更多關於Go語言編程的內容

歡迎關注曉代碼公衆號,和你們一塊兒學習吧

image.png
相關文章
相關標籤/搜索