跳至主要内容

5 篇文章 含有標籤「go web」

檢視所有標籤

Go Web 程式設計入門教學:Web 基礎

· 閱讀時間約 4 分鐘

Go Web 程式設計入門教學

前面幾個單元中我們介紹了許多 [Go 程式語言](https://en.wikipedia.org/wiki/Go_(programming_language) 的基本語法,讓我們了解了 Go 程式語言的用法。接下來我們將透過 Go 來架設簡單的 Web Server。

Web 基本工作流程

Go Web 程式設計入門教學

在我們平常透過瀏覽器(Browser)瀏覽網站時,其背後事實上進行了一連串 Client 客戶端和 Server 伺服器端的互動,以下介紹 Web Server 工作流程簡介:

  1. 使用者在瀏覽器(Browser)網址列輸入 URL,瀏覽器會透過 DNS 伺服器進行解析,取得 Domain 對應伺服器(Server)的 IP 位置
  2. 找到對應 Server IP 後,Client 透過 TCP/IP 協定建立到 Server 的 TCP 連接
  3. Client 向 Server 發送 http 協定請求(request)封包,請求 server 資料
  4. 若請求資源中有動態網站的內容,Server 端會先呼叫伺服器端的程式語言解譯引擎負責處理內容。Server 將組好的內容向 Client 發送 http 協定回應(response)封包
  5. Client 和 Server 中斷 TCP 連線,等待下一次請求。由 Client 解析收到的回應(response)封包內容(body),在瀏覽器繪製 HTML/CSS/JavaScript 檔案內容

Go Web 程式設計入門教學

  • URL 解析

一般 URL(Uniform Resource Locator)結構大概長這樣:

Scheme://host{:port#}/path/.../[?query-string][#anchor]
  1. scheme:底層使用的協定(例如:https、http 或 ftp 等)
  2. host:http 伺服器 ip 位置或 domain
  3. port:http 預設是 80 可以省略,如果是使用其他則需要填寫,可以想成是 ip 的名牌號碼
  4. path:資源路徑
  5. query-string:使用 get 傳送的參數
  6. anchor:記錄超連結錨點
  • DNS(Domain Name System)解析路徑

    1. 輸入網址,查找本機的 host 檔案
    2. 若 host 沒有 domain/ip 對應,則查找本機的 DNS 解析器快取
    3. 若 host/本機 DNS 快取都沒有 domain 對應則解析 TCP/IP 參數中設定的第一個 DNS 伺服器或其快取回傳(不具權威性)
    4. 若都故障,則會由 domain 右往左查找對應 DNS 伺服器(轉發/非轉發模式),回傳給本機 DNS 伺服器
  • HTTP request 請求解析 接著我們聊聊在 HTTP 協定中有定義許多和伺服器互動的方式,最基本的有四種:GETPOSTPUTDELETE,分別對應資源的查增更刪,最常見的舊是 GETPOST

    其中 GET 會把傳送資料放在網址後面,資料為明碼且有長度限制,一般用於查找資料。而 POST 資料傳遞主要是放在 http request 的 body 中,所以新增資料或是傳遞較敏感資料通常會用 POST 傳送

  • HTTP response 回應解析 http response 封包組成由版本編號、狀態碼、狀態訊息組成

    HTTP 狀態碼是使用三位數字組成,在 HTTP/1.1 中定義五大類狀態碼:

    1XX 提示訊息 2XX 成功 3XX 重新導向 4XX client 錯誤 5XX server 錯誤

使用 Go 架設基本 Web Server

在 Go 中可以使用 net/http 套件建立 Web 伺服器:

  1. Request:使用者請求的資訊,包含 post, get, cookie 等
  2. Response:伺服器需要回饋給使用者的資訊
  3. Conn:使用者請求每次產生連結
  4. Handler:處理請求和產生傳回資訊的處理邏輯
package main

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

// 處理函式
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world!")
}

func main() {
// 網址對應處理函式
http.HandleFunc("/", helloHandler)
// 監聽通訊 port
err := http.ListenAndServe(":7777", nil)
if err != nil {
log.Fatal("ListenAndServe", err)
} else {
log.Println("listen 7777")
}
}

總結

以上就是關於 Go 程式語言的 Web 基礎和 http 協定簡介,接下來的文章我們將透過 Golang Web 程式設計來學習 Go 這個程式語言的方方面面。

參考文件

  1. A tour of go
  2. Go Tutorial
  3. Go by Example
  4. Go Programming Language: An Introductory Tutorial
  5. Go tour Exercise
  6. Ubuntu Go install

(image via slidesharecdnwebsiteoptimization

Go Web 程式設計入門教學:語法基礎之函式(function)篇

· 閱讀時間約 4 分鐘

Go Web 程式設計入門教學

前面單元我們介紹了如何使用流程控制改變我們的程式執行順序,接下來的單元我們將透過 Golang Web 程式設計來學習 Go 這個程式語言。而在這個單元中我們將介紹 Go 函式的使用。程式語言唯有動手作才能學的好,你可以參考之前的文章建置開發環境或是使用線上開發環境進行學習。

函式簡介

有經驗的程式設計都知道程式撰寫的維護性很重要,其中模組化就是很重要的元素。當我們有一組程式出現過兩三次,那就很適合把它當做函式包裝起來。在程式語言中函式和數學上的函數有蠻多類似之處。我們可以把函式想成是一個黑盒子,透過呼叫函式可以完成我們想要做的工作,可能是傳入參數相加或是執行某段沒有回傳值的程式碼。

// 有一個關鍵字 func 其後接函式命名,可以傳入參數名稱和其資料型別(也可以不傳參數),後面是帶若有回傳值時的回傳值名稱和資料型別(也可以沒有回傳值)
func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
// 若有回傳值
return value1, value2
}
  1. 基本函式 基本款的函式就是有函式名稱,傳入參數和回傳值:

    package main

    import "fmt"

    func add(a, b int) int { // 當只傳一個回傳值且沒有定義回傳值變數時可以簡化括號
    return a + b
    }

    func main() {
    fmt.Println(add(1, 2))
    }
  2. 多回傳值

    package main

    import "fmt"

    func addAndProduct(a, b int) (int, int) { // 多回傳值要用括號括起
    return a + b, a * b
    }

    func main() {
    fmt.Println(addAndProduct(1, 2))
    }
  3. 長度不固定參數

    func argFunc(arg ...int) {}
  4. 傳值與傳指標
    一般來說我們傳入函式的參數是複製一份傳入,改動參數不會影響原有值。若今天我們傳入的不是複製值而是記憶體位置的指標,則會更改到原有值。

    package main

    import "fmt"

    func add(a int) int {
    return a + 10
    }

    func main() {
    a := 1
    fmt.Println(add(a)) // 11
    fmt.Println(a) // 1
    }

    換傳指標進去:

    package main

    import "fmt"

    func add(a *int) int {
    *a = *a + 10
    return *a
    }

    func main() {
    a := 1
    fmt.Println(add(&a)) // 11
    fmt.Println(a) // 11
    }
  5. defer 採用後進先出方式在函式全部執行結束前執行,常用於開啟資源後關閉檔案:

    func ReadFile() bool {
    file.Open("./file.txt")
    defer file.Close()
    if failureA {
    return false
    }
    if failureB {
    return false
    }
    return true
    }
  6. 函式當做值和類型

    type test func(int) (bool)

    func testIt(f test, a int) {

    }
  7. Panic、Recover 中斷程式進入 panic 狀態,用 Recover 可以恢復

模組

  1. main 函式和 init 函式

    當程式很複雜時,可以拆成不同 package 和檔案,其中 package main 為必要,其於 package 可以放置其他函式,在 Go 中函式或變數開頭大寫代表公有露出可以讓其他套件使用,反之為私有。其中 main 和 init 是保留函式,init 函式可以用於所有 package,main 用於 package main。Go 語言會自動呼叫兩者,init 是可選的,程式初始化是從 main 開始,如果有匯入其他套件會在編譯時依序匯入。如果有一個套件被引入多次,只會被引入一次。

    相對路徑:

    import "./model" // 同一目錄的 model 下

    絕對路徑:

    import "xxx/model" // gopath/src/xxx/model

    一般引用套件用法:

    import (
    "fmt"
    )

    fmt.Println("hi")

    點用法:

    import (
    . "fmt"
    )

    Println("hi")

    別名:

    import (
    f "fmt"
    )

    f.Println("hi")

    只執行套件中 init,不使用裡面函式:

    import (
    _ "fmt"
    )

總結

以上就是關於 Go 程式語言的基本語法中流程控制介紹,接下來的文章我們將透過 Golang Web 程式設計來學習 Go 這個程式語言的方方面面。

參考文件

  1. A tour of go
  2. Go Tutorial
  3. Go by Example
  4. Go Programming Language: An Introductory Tutorial
  5. Go tour Exercise
  6. Ubuntu Go install
  7. 從Go看現代程式語言

(image via cuelogic

Go Web 程式設計入門教學:語法基礎之流程控制(flow control)篇

· 閱讀時間約 4 分鐘

Go Web 程式設計入門教學

前面單元我們介紹了如何建置 Go 變數和資料型別的使用,接下來的單元我們將透過 Golang Web 程式設計來學習 Go 這個程式語言。而在這個單元中我們將介紹 Go 的流程控制的使用。程式語言唯有動手作才能學的好,你可以參考之前的文章建置開發環境或是使用線上開發環境進行學習。

流程控制簡介

一般而言,程式語言是由上往下執行,若我們需要程式依照我們設計的邏輯方向執行就需要流程控制的協助。在這邊主要談的流程控制有三部分:條件判斷、迴圈循環、跳躍控制。

我們使用制做菜脯蛋食譜步驟來講解範例:

  1. 放點油
  2. 打蛋
  3. 如果喜歡蔥花可以加入蔥花,如果喜歡菜脯可以加入菜脯(程式術語:if...else 條件判斷)
  4. 放入少許鹽巴
  5. 中火快炒,翻五次面(程式術語:for 迴圈)
  6. 當看到蛋面呈現金黃色時可以起鍋,結束料理(程式術語:while 迴圈)
  7. 好吃的蔥花蛋或菜脯蛋上桌

首先介紹,條件判斷,如果 if...。條件判斷是一種邏輯判斷,當符合條件就怎麼樣,不符合條件就怎麼樣。

  1. if...else

    package main

    import "fmt"

    var taste = "菜脯蛋" // 喜歡菜脯蛋

    if taste == "菜脯蛋" {
    fmt.Println("加入菜脯")
    } else {
    fmt.Println("加入蔥花")
    }

    Go 語言中除了條件判斷不用加 () 外,也可以在條件判斷敘述宣告變數,但只會存活於條件邏輯區塊使用上。

    package main

    import "fmt"

    if taste := "蔥花蛋"; taste == "菜脯蛋" {
    fmt.Println("加入菜脯")
    } else {
    fmt.Println("加入蔥花")
    }

    fmt.Println(taste) // 編譯錯誤,條件判斷敘述宣告的變數,只會存活於條件邏輯區塊使用上
  2. goto Go 中還提供了 goto 語法,讓你可以直接跳躍到某定義區塊,但建議小心使用。

    package main

    import "fmt"

    func main() {
    num := 91

    if num >= 60 {
    fmt.Println("hi true")
    goto PASS
    } else {
    fmt.Println("hi false")
    }
    PASS:
    fmt.Println("hi pass")
    }
  3. for 迴圈 在 go 中 for 迴圈的功能強大,既可以被當做循環讀取資料,又可以當做 while 來控制邏輯,還能反覆操作運算,以下介紹 for 語法:

    for 變數宣告或函式回傳值; 條件判斷; 每輪結束時操作 {
    // ...
    }

    我們接著使用食譜範例,中火快炒,翻五次面:

    package main

    import "fmt"

    func main() {
    for index := 0; index < 5; index++ {
    fmt.Println("翻面", index + 1, "次")
    }
    }

    當我們不知道具體要迴圈幾次時可以使用 while,但由於 Go 中沒有 while 關鍵字,當忽略了 ;,就可以當 while 迴圈使用:

    package main

    import "fmt"

    // 從 1 加到 10
    func main() {
    sum := 0
    i := 0
    for i <= 10 {
    sum += i
    i++
    }
    fmt.Println(sum)
    }

    使用 break 和 continue 可以跳出整個循環和跳過當下:

    package main

    import "fmt"

    // 從 1 加到 10
    func main() {
    sum := 0
    i := 0
    for i <= 10 {
    if i == 3 {
    break; // continue 跳過 3,break 到 3 整個循環跳出
    }
    sum += i
    i++
    }
    fmt.Println(sum)
    }

    善用 for 也可以把 slicemap 資料一一取出:

    package main

    import "fmt"

    for key, value := range map { // 也可以忽略其中一值,for _, value := range map
    fmt.Println(key, value)
    }
  4. switch 當我們需要寫很多 if...else 時就是使用 switch 的好時機:

    package main

    import "fmt"

    func main() {
    i := 2
    switch i {
    case 1:
    fmt.Println("hello:", i) // go 中不用加 break 會自己跳出不會往下執行
    case 2:
    fmt.Println("hello:", i) // 加上 fallthrough 可以強制往下執行
    fallthrough
    default:
    fmt.Println("hello: default")
    }
    }

總結

以上就是關於 Go 程式語言的基本語法中流程控制介紹,接下來的文章我們將透過 Golang Web 程式設計來學習 Go 這個程式語言的方方面面。

參考文件

  1. A tour of go
  2. Go Tutorial
  3. Go by Example
  4. Go Programming Language: An Introductory Tutorial
  5. Go tour Exercise
  6. Ubuntu Go install
  7. 從Go看現代程式語言

(image via cuelogic

Go Web 程式設計入門教學:語法基礎之變數(variable)和資料型別(type)篇

· 閱讀時間約 5 分鐘

Go Web 程式設計入門教學

前面單元我們介紹了如何建置 Go 開發環境,接下來的單元我們將透過 Golang Web 程式設計來學習 Go 這個程式語言。而在這個單元中我們將介紹 Go 的變數和常數宣告以及資料型別的使用。程式語言唯有動手作才能學的好,你可以參考之前的文章建置開發環境或是使用線上開發環境進行學習。

定義變數和使用

變數是程式語言中暫存資料的盒子,在 Go 中比較特別的是定義變數有多種方式(特別的是 Go 語言和 C 語言在設計上比較不同的地方是 Go 語言把變數型別宣告放在變數名稱後面),以下列出比較常見的變數使用方式:

  1. 一般變數宣告

    // var 關鍵字 變數名稱 資料型別
    var varName type

    範例:

    var str string
  2. 定義多個變數

    var var1Name, varName2 type

    範例:

    var str1, str2 string
  3. 定義變數並初始化

    var varName type = value
  4. 同時初始化多個變數

    var varName1, varName2, varName3 type = v1, v2, v3
  5. 簡化宣告

    var varName1. varName2, varName3 = v1, v2, v3

    另外一種是使用 := 符號取代 vartype,但要注意的是這樣的方式只能在函式內部使用,若是在全域使用會出現編譯錯誤,一般使用 var 定義全域變數。它的變數生命週期為 block 內。

    package main

    import "fmt"

    var num = 10

    // 編譯錯誤
    str0 := "world"

    func main() {
    var str1 = "hello"
    str2 := "world"
    fmt.Println(num)
    fmt.Println(str1)
    fmt.Println(str2)
    if true {
    var str3 = "XD" // str3 := "XD"
    fmt.Println(num)
    fmt.Println(str1)
    fmt.Println(str2)
    fmt.Println(str3)
    }
    fmt.Println(num)
    fmt.Println(str1)
    fmt.Println(str2)
    // 變數生命週期結束 undefined 錯誤
    fmt.Println(str3)
    }

    值得注意的若是在函式內宣告但沒使用會出現編譯錯誤:

    package main

    import "fmt"

    var num = 10

    func main() {
    var str = "hello"
    fmt.Println(str)
    }
    ./main.go:10:6: str declared and not used

定義常數

常數和變數不同是在編譯時就確認值,在程式執行期間不可以更改值。在 Go 程式語言使用 const 定義常數,其語法如下:

const constName = value
const Pi = 3.14
const Name string = "Mark"

內建簡單資料型別

  1. 布林值 在 Go 布林值是 truefalse,預設為 false

    var isActived = true
  2. 數字 在 Go 語言中主要分為 intuint 兩類型數字資料型別,個別之間還有位元可以做選擇,例如:int32。注意兩種數字資料型別不能互相設定或操作(例如:相加)

    var num = 12
  3. 字串 Go 語言中使用 UTF-8 字元編碼,使用 "" 來包裹字串:

    var str string = "hello"
    str[1] // e

    ch = []byte(str)
    ch[1] = 'w'
    str2 = string(ch)
    fmt.Println(str2) // hwllo
  4. 錯誤類型 在 Go 語言中有一個 error 類型,在套件中也有個 errors 負責處理錯誤訊息:

    import errors
    err := errors.New("throw error")

    if err != nil {
    fmt.Println(err)
    }

複雜資料型別

  1. array array 就是一般程式語言的陣列,基本上和其他程式語言相同:

    // 變數名稱 [長度]類別
    var arrayName [n]type

    陣列長度宣告後不能改變,傳入函式為副本,若需要傳指標進去可以使用 slice。實際使用方式:

    // 宣告長度為 10 類型為 int 的陣列
    var arr [10]int
    arr[0] = 7
    arr[1] = 13

    a := [3]int{1, 2, 3}
    b := [10]int{1, 2, 3}
    // 自動計算元素長度
    c := [...]int{1, 2, 3}
    // 二維陣列
    dArry := [2][4]{[3]{1, 2, 3}, [3]{2, 3, 4}}
  2. slice 有時候我們不會一開始就知道需要宣告多長的陣列,這時就需要使用動態陣列(是一個參考類型,總是指向底層 array):slice,其使用方式:

    var sliceName = []type

    實際使用:

    slice = []byte{1, 3, 4}
    array = [3]int{1, 3, 4}
    bySlice :=
  3. map map 和其他程式語言的 dict 和 hash map 相似,使用方式:

    var mapName = map[keyType]valueType

    key 可以是除了 int 外其他類型,取值使用 key 取值:

    // 第一種宣告方式
    var numbers map[string] int
    // 第二種宣告方式
    numbers := make(map[string]int)
    numbers["one"] = 1
    numbers["two"] = 7
    numbers["three"] = 13
    fmt.Println("three", numbers["three"])

    // key 數量
    m := map[string]int {"1": 1, "3": 2}
    fmt.Println(len(m))

    // map 新增、刪除、修改、查找
    numbers["three"] = 13
    value, ok := numbers["three"]
    numbers["three"] = 17
    delete(numbers["three"])

    此外 map 是無序的,也是個參考類型指到底層:

    numbers := make(map[string]int)

    numbers["three"] = 13
    numbers2 := numbers
    numbers2["three"] = 1 // numbers["three"] 也變成 1

make、new 比較

make 一般用於內建資料型別(map、slice 和 channel)的記憶體分配,而 new 用於各種類型記憶體分配。make 回傳有初值的 T 類型,而 new 回傳指標。

總結

以上就是關於 Go 程式語言的基本語法中的變數和資料型別介紹,接下來的文章我們將透過 Golang Web 程式設計來學習 Go 這個程式語言的方方面面。

參考文件

  1. A tour of go
  2. Go Tutorial
  3. Go by Example
  4. Go Programming Language: An Introductory Tutorial
  5. Go tour Exercise
  6. Ubuntu Go install
  7. 從Go看現代程式語言

(image via cuelogic

Go Web 程式設計入門教學:基礎介紹與環境建置

· 閱讀時間約 4 分鐘

Go Web 程式設計入門教學

[Go 程式語言](https://en.wikipedia.org/wiki/Go_(programming_language) 是 Google 推出的靜態程式語言,其特色在於核心語法和關鍵字非常精簡(全部只有 25 個關鍵字!)並擷取了靜態語言的效能和動態語言的開發效率的優點,具備垃圾回收、快速編譯等特性,且針對平行化程式設計在使用上非常方便。接下來的文章我們將透過 Golang Web 程式設計來學習 Go 這個程式語言。程式語言唯有動手作才能學的好,你可以參考本篇文章建置開發環境或是使用線上開發環境進行學習。

Go 環境建置

安裝方式:

  1. 官網套裝安裝,線上也有官方提供的 playground 線上執行環境可以使用

  2. 使用套件管理工具 homebrew(mac)、apt-get(linux) 等進行安裝

    例如,在 linux 上安裝:

    $ sudo apt-get install golang-go

    或是主動宣告版本

    $ sudo apt-get install golang-1.8-go

    在 mac 上安裝:

    $ brew install go
  3. 使用 gcc、MinGW(windows)等編譯器編譯原始 Go 檔案

對於一般初學者來說,可以使用官網或是套件管理工具來安裝,可以留意環境變數是否有設定成功。

若有成功安裝,可以打開終端機執行 go version 會出現相關版本訊息,以下是 mac 的範例:

$ go version
go version go1.9 darwin/amd64

在 Go 中也提供了許多方便指令,方便我們編譯、測試和執行程式:

Go Web 程式設計入門教學

編譯檔案

$ go build

執行單元測試(unit testing),Go 一開始就內建了測試的機制,執行 go test 的話,會自動讀取套件目錄中的 *_test.go 來進行編譯、測試

$ go test

讓程式可以格式化 formatting,符合 go 的 convention

$ go fmt

安裝套件

$ go get

靜態分析潛在 bug

$ go vet

可以快速 build 並執行程式

$ go run

展示 go 相關文件

$ godoc

重新命名變數和函式

$ gorename

產生程式碼

$ go generate

你的第一個 Go 程式

在 Go 中程式運行的入口是套件 main。在這個程式中使用並導入了套件 "fmt",在 Go 程式中程式執行入口是 main function,若成功在終端機執行 $ go run,則會在終端機印出 Hello, World! 的 Go 程式,恭喜完成你的第一個 Go 程式了!

// 宣告程式屬於哪個 package
package main

// 引入套件
import (
"fmt"
)

// 程式執行入口
func main() {
// 使用 fmt 套件印出字串 word,使用 := 簡化原本變數宣告 var word string = "Hello, World!"
word := "Hello, World!"
fmt.Println(word)
}

另外一個範例是引入了 math/rand 套件產生隨機整數(由於環境中 seed 一樣所以會印出同樣值)

package main

import (
"fmt"
"math/rand"
)

func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}

Go 有支援許多網路程式開發的套件,可以用很簡單的幾行就完成網路伺服器的建置:

package main

import (
"io"
"net/http"
)

// 處理 request 和 response 的函式
func hello(w http.ResponseWriter, r *http.Request) {
// 印出 hello world
io.WriteString(w, "Hello world!")
}

func main() {
// router 讓網址可以對應處理函式
http.HandleFunc("/", hello)
// 監聽 8000 port
http.ListenAndServe(":8000", nil)
}

總結

以上就是關於 Go 程式語言的基本教學介紹和環境建置,接下來的文章我們將透過 Golang Web 程式設計來學習 Go 這個程式語言的方方面面。

參考文件

  1. A tour of go
  2. Go Tutorial
  3. Go by Example
  4. Go Programming Language: An Introductory Tutorial
  5. Go tour Exercise
  6. Ubuntu Go install
  7. 從Go看現代程式語言

(image via cuelogic