[Golang] Попробуйте обработать веб-запросы


Введение

На этот раз я попробую обработать веб-запросы.
Я буду использовать проект, который я создал в прошлый раз.

  • [Golang] Попробуйте WebSocket

Обработка веб-запросов

Сначала я попробую обработать веб-запросы.
Поскольку я никогда не пробовал обращаться к базе данных в Golang, в этот раз я попробую методы GET и POST.

Разделение операций по методам HTTP

Поскольку в «http.Handle» и «http.HandleFunc» нет функций для указания HTTP-методов, я не могу добавить одинаковые маршруты для каждого HTTP-метода.

main.go

package main

import (
    "html/template"
    "log"
    "net/http"
    "path/filepath"
    "sync"
)
...
func main() {
...
    http.HandleFunc("/webrequest", webRequestHandler)
    // panic: http: multiple registrations for /webrequest
    http.HandleFunc("/webrequest", func(_ http.ResponseWriter, _ *http.Request) {
        log.Println("webrequest2")
    })
...
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Поэтому мне нужно самостоятельно маршрутизировать запросы для каждого HTTP-метода следующим образом.

main.go

...
func main() {
...
    http.HandleFunc("/webrequest", webRequestHandler)
...
}
Войти в полноэкранный режим Выйти из полноэкранного режима

webRequestSample.go

package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        // For GET request
        break
    case http.MethodPost:
        // For POST request
        break
    }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Получение параметров запроса

Я могу получить параметры запроса из «http.Request».

webRequestSample.go

...
func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    name, err := getParam(r, "name")
    if err == nil {
        log.Println(name)
    } else {
        log.Println(err)
    }
...
}
func getParam(r *http.Request, key string) (string, error) {
    result := r.URL.Query().Get(key)
    if len(result) <= 0 {
        return "", errors.New(fmt.Sprintf("no value: %s", key))
    }
    return result, nil
}
Войти в полноэкранный режим Выход из полноэкранного режима
  • пакет url — net/url — pkg.go.dev
  • net/http пакет get Query Params in Go(Golang) — Добро пожаловать в Golang на примере

Возвращает форматированные строковые значения

webRequestSample.go

...
func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        name, err := getParam(r, "name")
        if err != nil {
            fmt.Fprint(w, "The parameters have no names")
            return
        }
        fmt.Fprintf(w, "Hi there, I love %s!", name)
        break
...
    }
}
...
Вход в полноэкранный режим Выход из полноэкранного режима
  • Написание веб-приложений — Язык программирования Go

Возвращение значений JSON (+ чтение значений из тела)

webRequest.page.ts

export function send() {
    fetch(targetUrl, 
        {
            method: "POST",
            body: JSON.stringify({ messageType: "text", data: "Hello" }),
        })
        .then(res => res.json())
        .then(json => console.log(json))
        .catch(err => console.error(err));
}
Вход в полноэкранный режим Выход из полноэкранного режима

webRequestSample.go

...
type sampleResult struct {
    Message      string `json:"message"`
    Succeeded    bool   `json:"succeeded"`
    ErrorMessage string `json:"errorMessage"`
}

func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
...
    case http.MethodPost:
        returnValue := &sampleResult{}
        w.Header().Set("Content-Type", "application/json")
        // read values from HTTP request body
        body, readBodyError := ioutil.ReadAll(r.Body)

        if readBodyError != nil {
            returnValue.Succeeded = false
            returnValue.ErrorMessage = "Failed reading values from body"
            failedReadingData, _ := json.Marshal(returnValue)
            w.Write(failedReadingData)
            return
        }
        wsMessage := &websocketMessage{}
        convertError := json.Unmarshal(body, &wsMessage)
        if convertError != nil {
            returnValue.Succeeded = false
            returnValue.ErrorMessage = "Failed converting to WebSocketMessage"
            failedConvertingData, _ := json.Marshal(returnValue)
            w.Write(failedConvertingData)
            return
        }
        w.WriteHeader(200)
        returnValue.Message = fmt.Sprintf("%s_1", wsMessage.Data)
        returnValue.Succeeded = true
        returnValue.name = "hello world"
        data, _ := json.Marshal(returnValue)

        w.Write(data)
        break
    }
}
...
Войти в полноэкранный режим Выйти из полноэкранного режима

Результат

{
    "message": "Hello_1",
    "succeeded": true,
    "errorMessage": ""
}
Вход в полноэкранный режим Выход из полноэкранного режима

структуры для json.Marshal & json.Unmarshal

Я определил «sampleResult» следующим образом.

type sampleResult struct {
    message      string
    succeeded    bool
    errorMessage string
}
Вход в полноэкранный режим Выход из полноэкранного режима

Поскольку «json.Marshal» и «json.Unmarshal» игнорируют приватные свойства, результаты всегда получались пустыми 😛

  • пакет json — кодирование/json — pkg.go.dev
  • Возврат тела JSON в HTTP-ответе в Go (Golang) — Welcome To Golang By Example

Возвращение данных файла

webRequestSample.go

...
func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        name, err := getParam(r, "name")
        if err != nil {
            log.Println(err.Error())
            return
        }
        // Search file from current directory
        cur, _ := os.Getwd()
        file, fileErr := os.Open(fmt.Sprintf("%s/files/%s", cur, name))
        if fileErr != nil {
            log.Println(fileErr.Error())
            w.WriteHeader(404)
            return
        }
        // Get file infomations
        fileinfo, staterr := file.Stat()
        if staterr != nil {
            log.Println(staterr.Error())
            w.WriteHeader(404)
            return
        }
        // To download file, I set "application/octet-stream" as Content-Type
        w.Header().Set("Content-Type", "application/octet-stream")
        // set its file name
        cd := mime.FormatMediaType("attachment", map[string]string{"filename": fileinfo.Name()})
        w.Header().Set("Content-Disposition", cd)
        http.ServeContent(w, r, fileinfo.Name(), fileinfo.ModTime(), file)
        break
...
Вход в полноэкранный режим Выход из полноэкранного режима

Имя файла

Сначала я попробовал прочитать файл и вернуть массив байтов, как показано ниже.

...
        // Get file infomations
        fileinfo, staterr := file.Stat()
        if staterr != nil {
            log.Println(staterr.Error())
            w.WriteHeader(404)
            return
        }
        // Read file
        fileData := make([]byte, fileinfo.Size())
        fileSize, loadErr := file.Read(fileData)
        if loadErr != nil {
            log.Println(loadErr.Error())
            w.WriteHeader(404)
            return
        }
        // To download file, I set "application/octet-stream" as Content-Type
        w.Header().Set("Content-Type", "application/octet-stream")
        w.Write(fileData)
        break
...
Вход в полноэкранный режим Выйти из полноэкранного режима

Но загруженные файлы всегда имели имя «webrequest», поэтому я перешел на использование «http.ServeContent».

  • http пакет — net/http — pkg.go.dev
  • Как загрузить файл в браузере с сервера Go — StackOverflow
  • Получить имя файла, размер, биты разрешения, режим, время модификации в Go (Golang) — Welcome To Golang By Example

Оцените статью
Procodings.ru
Добавить комментарий