使用ajax和golang的Form實現bs異步交互

Ajax:Asynchronous Javascript And XML(異步 JavaScript 和 XML)。

Ajax 的核心是 js 對象:XMLHttpRequest。

XMLHttpRequest 對象提供了對 HTTP 協議的完全的訪問,包括做出 POST 和 HEAD 請求以及普通的 GET 請求的能力。XMLHttpRequest 可以同步或異步地返回 Web 服務器的響應,並且能夠以文本或者一個 DOM 文檔的形式返回內容。

現代的近乎所有的瀏覽器對其都有很好的支持,但IE5, IE6需使用其內置ActiveXObject()函數構造的對象。

關於XMLHttpRequest對象:
屬性:

readyState: HTTP 請求的狀態.當一個 XMLHttpRequest 初次創建時,這個屬性的值從 0 開始,直到接收到完整的 HTTP 響應,這個值增加到 4。

狀態 名稱 描述
0 Uninitialized 初始化狀態。XMLHttpRequest 對象已創建或已被 abort() 方法重置。
1 Open open() 方法已調用,但是 send() 方法未調用。請求還沒有被髮送。
2 Sent Send() 方法已調用,HTTP 請求已發送到 Web 服務器。未接收到響應。
3 Receiving 所有響應頭部都已經接收到。響應體開始接收但未完成。
4 Loaded HTTP 響應已經完全接收。

readyState 的值不會遞減,除非當一個請求在處理過程中的時候調用了 abort() 或 open() 方法。每次這個屬性的值增加的時候,都會觸發 onreadystatechange 事件句柄。

responseText: 目前爲止爲服務器接收到的響應體(不包括頭部),或者如果還沒有接收到數據的話,就是空字符串。如果響應包含了爲響應體指定字符編碼的頭部,就使用該編碼。否則,假定使用 Unicode UTF-8。

responseXML: 對請求的響應,解析爲 XML 並作爲 Document 對象返回。

status: 由服務器返回的 HTTP 狀態代碼,如 200 表示成功,而 404 表示 “Not Found” 錯誤。當 readyState 小於 3 的時候讀取這一屬性會導致一個異常。

statusText: 這個屬性用名稱而不是數字指定了請求的 HTTP 的狀態代碼。也就是說,當狀態爲 200 的時候它是 “OK”,當狀態爲 404 的時候它是 “Not Found”。和 status 屬性一樣,當 readyState 小於 3 的時候讀取這一屬性會導致一個異常。

方法:

abort()
取消當前響應,關閉連接並且結束任何未決的網絡活動。

這個方法把 XMLHttpRequest 對象重置爲 readyState 爲 0 的狀態,並且取消所有未決的網絡活動。例如,如果請求用了太長時間,而且響應不再必要的時候,可以調用這個方法。

getAllResponseHeaders()
把 HTTP 響應頭部作爲未解析的字符串返回。

如果 readyState 小於 3,這個方法返回 null。否則,它返回服務器發送的所有 HTTP 響應的頭部。頭部作爲單個的字符串返回,一行一個頭部。每行用換行符 “\r\n” 隔開。

getResponseHeader()
返回指定的 HTTP 響應頭部的值。其參數是要返回的 HTTP 響應頭部的名稱。可以使用任何大小寫來制定這個頭部名字,和響應頭部的比較是不區分大小寫的。

該方法的返回值是指定的 HTTP 響應頭部的值,如果沒有接收到這個頭部或者 readyState 小於 3 則爲空字符串。如果接收到多個有指定名稱的頭部,這個頭部的值被連接起來並返回,使用逗號和空格分隔開各個頭部的值。

open()
初始化 HTTP 請求參數,例如 URL 和 HTTP 方法,但是並不發送請求。

send()
發送 HTTP 請求,使用傳遞給 open() 方法的參數,以及傳遞給該方法的可選請求體。

setRequestHeader()
向一個打開但未發送的請求設置或添加一個 HTTP 請求。

實例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<h1>Ajax 發送 get 請求</h1>
<input type="button" value="發送get_ajax請求" id='btnAjax'>

<script type="text/javascript">
    // 綁定點擊事件
    document.querySelector('#btnAjax').onclick = function () {
        // 發送ajax 請求 需要 五步

        // (1)創建異步對象
        var ajaxObj = new XMLHttpRequest();

        // (2)設置請求的參數。包括:請求的方法、請求的url。
        ajaxObj.open('get', '02-ajax.php');

        // (3)發送請求
        ajaxObj.send();

        //(4)註冊事件。 onreadystatechange事件,狀態改變時就會調用。
        //如果要在數據完整請求回來的時候才調用,我們需要手動寫一些判斷的邏輯。
        ajaxObj.onreadystatechange = function () {
            // 爲了保證 數據 完整返回,我們一般會判斷 兩個值
            if (ajaxObj.readyState == 4 && ajaxObj.status == 200) {
                // 如果能夠進到這個判斷 說明 數據 完美的回來了,並且請求的頁面是存在的
                // 5.在註冊的事件中 獲取 返回的 內容 並修改頁面的顯示
                console.log('數據返回成功');

                // 數據是保存在 異步對象的 屬性中
                console.log(ajaxObj.responseText);

                // 修改頁面的顯示
                document.querySelector('h1').innerHTML = ajaxObj.responseText;
            }
        }
    }
</script>
</body>
</html>
值得注意的是:

在ajax使用POST方法提交數據的時候,需要將Request的Header設置request.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”);
關於Content-Type可以直接查看MDN ,順便一提,在chunk傳輸中都是先編碼(一般base64)然後再boundary分chunk傳輸。 在smtp協議裏面傳輸MIME數據也是這樣做的。

post使用Content-Type的目的在於讓serve端知曉數據應該如何解碼。


function getTextAreaContent(){
    var textdom = document.getElementById("textId0");
    
    if(1 == textdom.value.length)return;//1的原因見textarea的dom屬性
    commitRecord(textdom.value);
    textdom.select();
    //post record to server.
    var request = new XMLHttpRequest();
    request.open("POST", "/talk/post", true);
    request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
    request.send(textdom.value);
    //recv....
}
golang的Form調用

通過post提交的數據按照http協議規定當然是存在與Request的Body段中。所以可以直接通過Request::Body來獲取。
其次golang爲我們提供了form數據的解析方法:

	//post是可以提交文件的,文件在Request的Body中以base64編碼存儲
	//返回key對應的第一個文件,FormFile可能會調用ParseForm或者ParseMultipartForm,取決於Request的Content-Type
    func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)
    //返回key對應的第一個值,函數可能調用ParseForm或者ParseMultipartForm
    func (r *Request) FormValue(key string) string
    //MultipartReader returns a MIME multipart reader if this is a multipart/form-data or a multipart/mixed POST request, else returns nil and an error.
    func (r *Request) MultipartReader() (*multipart.Reader, error)
    //ParseForm populates r.Form and r.PostForm.
    func (r *Request) ParseForm() error
    //ParseMultipartForm parses a request body as multipart/form-data. 
    func (r *Request) ParseMultipartForm(maxMemory int64) error
    //PostFormValue returns the first value for the named component of the POST, PATCH, or PUT request body.
    func (r *Request) PostFormValue(key string) string

還需要知道的是Request具有Form,PostForm,MultipartForm三個字段,通過ParseForm()將form數據解析道Form和PostForm, ParseMultipartForm()將數據解析到MultipartForm。

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/postpage", func(w http.ResponseWriter, r *http.Request) {
		//接受post請求,然後打印表單中key和value字段的值
		if r.Method == "POST" {
			var (
				key   string = r.PostFormValue("key")//首先會調用ParseForm或者ParseMultipartForm
				value string = r.PostFormValue("value")
			)
			fmt.Printf("key is  : %s\n", key)
			fmt.Printf("value is: %s\n", value)
		}
	})

	err := http.ListenAndServe(":80", nil)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
}
Reference:

[1] https://www.w3school.com.cn/xmldom/dom_http.asp
[2] https://www.cnblogs.com/qianguyihao/p/8485028.html
[3] https://golang.google.cn/pkg/net/http/#Request

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