閱讀:《Golang web 應用開發》

閱讀:《Golang web 應用開發》

一. Web工作方式

上網過程

對於普通的上網過程,系統其實是這樣做的:瀏覽器本身是一個客戶端,當你輸入URL的時候,首先瀏覽器會去請求DNS服務器,通過DNS獲取相應的域名對應的IP,然後通過IP地址找到IP對應的服務器後,要求建立TCP連接,等瀏覽器發送完HTTP Request(請求)包後,服務器接收到請求包之後纔開始處理請求包,服務器調用自身服務,返回HTTP Response(響應)包;客戶端收到來自服務器的響應後開始渲染這個Response包裏的主體(body),等收到全部的內容隨後斷開與該服務器之間的TCP連接。

URL和DNS解析

URL解析格式:

scheme://host[:port#]/path/…/[?query-string][#anchor]
scheme 指定底層使用的協議(例如:http, https, ftp)
host HTTP服務器的IP地址或者域名
port# HTTP服務器的默認端口是80,這種情況下端口號可以省略。如果使用了別的端口,必須指明,例如 http://www.cnblogs.com:8080/
path 訪問資源的路徑
query-string 發送給http服務器的數據
anchor 錨

DNS解析過程
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CrJjkUgm-1572954425917)(1)]
通過上面的步驟,我們最後獲取的是IP地址,也就是瀏覽器最後發起請求的時候是基於IP來和服務器做信息交互的。

HTTP協議

  • 在HTTP中,客戶端總是通過建立一個連接與發送一個HTTP請求來發起一個事務
  • HTTP協議是無狀態的,同一個客戶端的這次請求和上次請求是沒有對應關係的,對HTTP服務器來說,它並不知道這兩個請求是否來自同一個客戶端。爲了解決這個問題, Web程序引入了Cookie機制來維護連接的可持續狀態。

HTTP請求包(瀏覽器信息)

Request

Request包分爲3部分,第一部分叫Request line(請求行), 第二部分叫Request header(請求頭),第三部分是body(主體)。header和body之間有個空行,請求包的例子所示:

GET /domains/example/ HTTP/1.1 //請求行: 請求方法 請求URI HTTP協議/協議版本
Host:www.iana.org //服務端的主機名
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 //瀏覽器信息
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 //客戶端能接收的MIME
Accept-Encoding:gzip,deflate,sdch //是否支持流壓縮
Accept-Charset:UTF-8,*;q=0.5 //客戶端字符編碼集
//空行,用於分割請求頭和消息體
//消息體,請求資源參數,例如POST傳遞的參數

HTTP協議定義了很多與服務器交互的請求方法,最基本的有4種,分別是GET,POST,PUT,DELETE。一個URL地址用於描述一個網絡上的資源,而HTTP中的GET, POST, PUT, DELETE就對應着對這個資源的查,增,改,刪4個操作。我們最常見的就是GET和POST了。GET一般用於獲取/查詢資源信息,而POST一般用於更新資源信息。

HTTP響應包

Respons

HTTP/1.1 200 OK //狀態行
Server: nginx/1.0.8 //服務器使用的WEB軟件名及版本
Date:Date: Tue, 30 Oct 2012 04:14:25 GMT //發送時間
Content-Type: text/html //服務器發送信息的類型
Transfer-Encoding: chunked //表示發送HTTP包是分段發的
Connection: keep-alive //保持連接狀態
Content-Length: 90 //主體內容長度
//空行 用來分割消息頭和主體
!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”… //消息體

二. Go搭建一個Web服務器

http包建立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)
	}
}

執行結果

在這裏插入圖片描述
在這裏插入圖片描述

三. Go創建Web服務器的幾種方式

http.HandleFunc函數

使用HandleFunc函數是http封裝好的一個函數,可以直接使用,第一個參數是web請求路徑,第二個參數是的func(writer http.ResponseWriter, request *http.Request)函數。
再使用http.ListenAndServe(":9090",nil)語句,監聽9090端口,運行程序後。
使用http://localhost:9090,便會輸出Hello astaxie!
其中http.ResponseWriter代表對客戶端的響應體,而http.Request代表客戶端發送服務器的請求數據。
http.Handle函數
跟HandleFunc一樣,Handle也是http封裝好的函數,第一個參數跟HandleFunc一樣,而第二個參數則是必須是實現了http.Handler接口的類型,http.Handler在http包的定義如下:

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

http.ServeMux
無論是使用http.Handle還是http.HandleFunc函數,其實底層代碼都是使用http.DefaultServeMux,DefaultServeMux的定義如下代碼所示:

var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux
type Controller struct {}
func (c Controller)ServeHTTP(writer http.ResponseWriter, request *http.Request){
    writer.Write([]byte("hello,1"));
}

func hello(writer http.ResponseWriter, request *http.Request) {
    writer.Write([]byte("hello,2"));
}

func main(){
    mux := &http.ServeMux{}
    mux.HandleFunc("/hello1",hello)
    mux.Handle("/hello2",http.HandlerFunc(hello))
    mux.Handle("/hello3",&Controller{})

    log.Fatal(http.ListenAndServe(":8080",mux))
}

http.Server
http.Server是http包中對web更加底層的支持,我們前面使用的方法,都是對http.Server的封裝而已,如果直接使用http.Server,則可以自定義更多的參數,如果連接超時等參數,因此我們下面直接使用http.Server開發Web服務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章