Go語言使用net/http實現(xiàn)簡單登錄驗證和文件上傳功能
最近再看Go語言web編程,go語言搭建Web服務(wù)器,既可以用go原生的net/http包,也可以用gin/fasthttp/fiber等這些Web框架。本博客使用net/http模塊編寫了一個簡單的登錄驗證和文件上傳的功能,在此做個簡單記錄。
代碼如下:
package main
import (
"fmt"
"html/template"
"io"
"log"
"net/http"
"os"
)
/*
go運行方式:
(1)解釋運行
go run main.go
(2)編譯運行
--使用默認(rèn)名
go build main.go
./main
--指定可執(zhí)行程序名
go build -o test main.go
./test
*/
// http://127.0.0.1:8181/login
func login(w http.ResponseWriter, r *http.Request) {
fmt.Println("method", r.Method)
if r.Method == "GET" {
t, _ := template.ParseFiles("login.html")
t.Execute(w, nil)
/*
//字符串拼裝表單
html := `<html>
<head>
<title>上傳文件</title>
</head>
<body>
<form enctype="multipart/form-data" action="http://localhost:8181/upload" method="post">
<input type="file" name="uploadfile" />
<input type="hidden" name="token" value="{
{.}}" />
<input type="submit" value="upload" />
</form>
</body>
</html>`
crutime := time.Now().Unix()
h := md5.New()
io.WriteString(h, strconv.FormatInt(crutime, 10))
token := fmt.Sprintf("%x", h.Sum(nil))
t := template.Must(template.New("test").Parse(html))
t.Execute(w, token)
*/
} else {
r.ParseForm()
fmt.Println("username", r.Form["username"])
fmt.Println("password", r.Form["password"])
fmt.Fprintf(w, "登錄成功")
}
}
// http://127.0.0.1:8181/upload
func upload(writer http.ResponseWriter, r *http.Request) {
//表示maxMemory,調(diào)用ParseMultipart后,上傳的文件存儲在maxMemory大小的內(nèi)存中,
//如果大小超過maxMemory,剩下部分存儲在系統(tǒng)的臨時文件中
r.ParseMultipartForm(32 << 10)
//根據(jù)input中的name="uploadfile"來獲得上傳的文件句柄
file, header, err := r.FormFile("uploadfile")
if err != nil {
fmt.Fprintf(writer, "上傳出錯")
fmt.Println(err)
return
}
defer file.Close()
/*
fmt.Printf("Uploaded File: %+v\n", header.Filename)
fmt.Printf("File Size: %+v\n", header.Size)
// 注意此處的header.Header是textproto.MIMEHeader類型 ( map[string][]string )
fmt.Printf("MIME Type: %+v\n", header.Header.Get("Content-Type"))
// 將文件保存到服務(wù)器指定的目錄(* 用來隨機數(shù)的占位符)
tempFile, err := ioutil.TempFile("uploads", "*"+header.Filename)
*/
fmt.Println("handler.Filename", header.Filename)
f, err := os.OpenFile("./filedir/"+header.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println(err)
fmt.Fprintf(writer, "上傳出錯")
return
}
defer f.Close()
io.Copy(f, file)
fmt.Fprintf(writer, "上傳成功")
}
func common_handle() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world !"))
})
http.HandleFunc("/login", login)
http.HandleFunc("/upload", upload)
}
func main1() {
common_handle()
//監(jiān)聽8181端口
err := http.ListenAndServe(":8181", nil)
if err != nil {
log.Fatal("err:", err)
}
}
// 聲明helloHandler
type helloHandler struct{}
// 定義helloHandler
func (m11111 *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world, this is my first golang programe !"))
}
func welcome(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Welcome to golang family !"))
}
func main2() {
a := helloHandler{}
//使用http.Handle
http.Handle("/hello", &a)
http.Handle("/welcome", http.HandlerFunc(welcome))
common_handle()
server := http.Server{
Addr: "127.0.0.1:8181",
Handler: nil, // 對應(yīng)DefaultServeMux路由
}
server.ListenAndServe()
}
func main() {
main2()
}login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>歡迎進(jìn)入首頁</title> </head> <body> <h3>登錄測試</h3> <hr/> <form action="http://localhost:8181/login" method="post"> <table border=0 title="測試"> <tr> <td>用戶名:</td> <td><input type="text" name="username"></td> </tr> <tr> <td>密碼:</td> <td><input type="password" name="password"></td> </tr> <tr> <td colspan=2> <input type="reset" /> <input type="submit" value="登錄" /> </td> </tr> </table> </form> <br> <h3>文件上傳測試</h3> <hr/> <form action="http://localhost:8181/upload" method="post" enctype="multipart/form-data"> <input type="file" name="uploadfile"/> <input type="submit" value="upload"> </form> </body> </html>
1.文件目錄結(jié)構(gòu)

2.編譯運行

3.用戶登錄
http://127.0.0.1:8181/login




4.文件上傳




5.mime/multipart模擬form表單上傳文件
使用mime/multipart包,可以將multipart/form-data數(shù)據(jù)解析為一組文件和表單字段,或者使用multipart.Writer將文件和表單字段寫入HTTP請求體中。
以下例子中首先打開要上傳的文件,然后創(chuàng)建一個multipart.Writer,用于構(gòu)造multipart/form-data格式的請求體。我們使用CreateFormFile方法創(chuàng)建一個multipart.Part,用于表示文件字段,將文件內(nèi)容復(fù)制到該Part中。我們還使用WriteField方法添加其他表單字段。然后,我們關(guān)閉multipart.Writer,以便寫入Content-Type和boundary,并使用NewRequest方法創(chuàng)建一個HTTP請求。我們將Content-Type設(shè)置為multipart/form-data,并使用默認(rèn)的HTTP客戶端發(fā)送請求。最后,我們讀取并處理響應(yīng)。
關(guān)于什么是multipart/form-data?multipart/form-data的基礎(chǔ)是post請求,即基于post請求來實現(xiàn)的multipart/form-data形式的post與普通post請求的不同之處體現(xiàn)在請求頭,請求體2個部分1)請求頭:必須包含Content-Type信息,且其值也必須規(guī)定為multipart/form-data,同時還需要規(guī)定一個內(nèi)容分割符用于分割請求體中不同參數(shù)的內(nèi)容(普通post請求的參數(shù)分割符默認(rèn)為&,參數(shù)與參數(shù)值的分隔符為=)。具體的頭信息格式如下:Content-Type: multipart/form-data; boundary=${bound}其中${bound} 是一個占位符,代表我們規(guī)定的具體分割符;可以自己任意規(guī)定,但為了避免和正常文本重復(fù)了,盡量要使用復(fù)雜一點的內(nèi)容。如:—0016e68ee29c5d515f04cedf6733比如有一個body為:--0016e68ee29c5d515f04cedf6733\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Disposition: form-data; name=text\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nwords words words wor=\r\nds words words =\r\nwords words wor=\r\nds words words =\r\nwords words\r\n--0016e68ee29c5d515f04cedf6733\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Disposition: form-data; name=submit\r\n\r\nSubmit\r\n--0016e68ee29c5d515f04cedf6733--
2)請求體:它也是一個字符串,不過和普通post請求體不同的是它的構(gòu)造方式。普通post請求體是簡單的鍵值對連接,格式如下:k1=v1&k2=v2&k3=v3而multipart/form-data則是添加了分隔符、參數(shù)描述信息等內(nèi)容的構(gòu)造體。具體格式如下:--${bound}Content-Disposition: form-data; name="Filename" //第一個參數(shù),相當(dāng)于k1;然后回車;然后是參數(shù)的值,即v1HTTP.pdf //參數(shù)值v1--${bound} //其實${bound}就相當(dāng)于上面普通post請求體中的&的作用Content-Disposition: form-data; name="file000"; filename="HTTP協(xié)議詳解.pdf" //這里說明傳入的是文件,下面是文件提Content-Type: application/octet-stream //傳入文件類型,如果傳入的是.jpg,則這里會是image/jpeg %PDF-1.5file content%%EOF--${bound}Content-Disposition: form-data; name="Upload"Submit Query--${bound}--都是以${bound}為開頭的,并且最后一個${bound}后面要加—
test.go
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path/filepath"
)
func main() {
// 需要上傳的文件路徑
filePath := "image_2023_06_29T11_46_39_023Z.png"
// 打開要上傳的文件
file, err := os.Open(filePath)
if err != nil {
fmt.Println("Failed to open file:", err)
return
}
defer file.Close()
// 創(chuàng)建multipart.Writer,用于構(gòu)造multipart/form-data格式的請求體
var requestBody bytes.Buffer
multipartWriter := multipart.NewWriter(&requestBody)
// 創(chuàng)建一個multipart.Part,用于表示文件字段
part, err := multipartWriter.CreateFormFile("uploadfile", filepath.Base(filePath))
if err != nil {
fmt.Println("Failed to create form file:", err)
return
}
// 將文件內(nèi)容復(fù)制到multipart.Part中
_, err = io.Copy(part, file)
if err != nil {
fmt.Println("Failed to copy file content:", err)
return
}
// 添加其他表單字段
multipartWriter.WriteField("title", "My file")
// 關(guān)閉multipart.Writer,以便寫入Content-Type和boundary
err = multipartWriter.Close()
if err != nil {
fmt.Println("Failed to close multipart writer:", err)
return
}
// 創(chuàng)建HTTP請求
req, err := http.NewRequest("POST", "http://127.0.0.1:8181/upload", &requestBody)
if err != nil {
fmt.Println("Failed to create request:", err)
return
}
// 設(shè)置Content-Type為multipart/form-data
req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
// 發(fā)送HTTP請求
client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
fmt.Println("Failed to send request:", err)
return
}
defer resp.Body.Close()
// 處理響應(yīng)
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Failed to read response:", err)
return
}
fmt.Println("Response:", string(respBody))
}編譯執(zhí)行:
go build test.go
./test
運行結(jié)果展示:


到此這篇關(guān)于Go語言使用net/http實現(xiàn)簡單登錄驗證和文件上傳功能的文章就介紹到這了,更多相關(guān)Go登錄驗證和文件上傳內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Golang中NewTimer計時器的底層實現(xiàn)原理
本文將主要介紹一下Go語言中的NewTimer,首先展示基于NewTimer創(chuàng)建的定時器來實現(xiàn)超時控制。接著通過一系列問題的跟進(jìn),展示了NewTimer的底層實現(xiàn)原理,需要的可以參考一下2023-05-05
執(zhí)行g(shù)o?build報錯go:?go.mod?file?not?found?in?current?dir
本文主要為大家介紹了執(zhí)行g(shù)o build報錯go:?go.mod?file?not?found?in?current?directory?or?any?parent?directory解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Go?Excelize?API源碼解析GetSheetFormatPr使用示例
這篇文章主要為大家介紹了Go?Excelize?API源碼解析GetSheetFormatPr使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08

