>  기사  >  백엔드 개발  >  Golang 웹: POST 메서드

Golang 웹: POST 메서드

WBOY
WBOY원래의
2024-07-17 04:22:30773검색

소개

이 시리즈 섹션에서는 golang에서 POST HTTP 요청을 보내는 방법을 살펴보겠습니다. 이 게시물의 다음 섹션에서는 기본 POST 요청을 보내고, HTTP 요청을 생성하고, json, 구조체를 요청 본문으로 구문 분석하고, 헤더를 추가하는 방법을 이해합니다. 우리는 golang 구조체/유형을 JSON 형식으로 마샬링하고, 요청에 파일을 보내고, 이 기사의 각 예제를 통해 양식 데이터를 처리하는 방법을 이해할 것입니다. 먼저 몇 가지 질문에 답해 보겠습니다.

POST 요청이란 무엇입니까?

POST 방식은 서버(인터넷상의 기계)에 데이터를 보내는 데 사용되는 요청 유형입니다.

레스토랑에서 주문을 한다고 상상해 보세요. GET 요청을 사용하면 웨이터에게 "어떤 종류의 피자가 있나요?"라고 묻는 것과 같습니다. 웨이터는 메뉴 옵션(서버에서 가져온 정보)을 알려줌으로써 응답합니다.

그러나 POST 요청은 완료된 주문을 웨이터에게 전달하는 것과 비슷합니다. 원하는 특정 피자, 크기 및 추가 토핑(보내는 데이터)을 알려줍니다. 그런 다음 웨이터는 이 정보(POST 요청)를 주방(서버)으로 다시 가져와 처리(주문 이행)합니다.

웹 개발 세계에서 POST 요청은 다음과 같은 용도로 자주 사용됩니다.

양식 제출(예: 문의 양식, 로그인 양식) 파일 업로드(예: 사진, 비디오) 새 계정 만들기 처리할 데이터 전송(예: 온라인 구매)

이 시나리오에서 POST 요청의 예는 다음과 같습니다.

POST /api/order HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 123

{
    "userID": 123,
    "orderID": 456,
    "items": [
        {
            "itemID": 789,
            "name": "Pizza",
            "quantity": 2
        },
        {
            "itemID": 999,
            "name": "Burger",
            "quantity": 1
        }
    ]
}

이 예에서는:

  • POST 방식은 서버에 데이터를 보내는 데 사용됩니다.

  • /api/order는 서버의 엔드포인트입니다.

  • application/json은 요청의 콘텐츠 유형입니다.

  • 123은 요청 내용 길이입니다.

  • {"userID": 123, "orderID": 456, "items": [{"itemID": 789, "name": "Pizza", "Quantity": 2}, {"itemID ": 999, "name": "Burger", "Quantity": 1}]}는 요청 본문입니다.

POST 요청이 필요한 이유는 무엇입니까?

HTTP 요청 세계에서는 POST 메서드를 사용하여 클라이언트(예: 사용자 브라우저)에서 서버로 데이터를 안전하게 보냅니다. GET 방식은 데이터 검색에 편리하지만 다음과 같은 제한 사항이 있기 때문에 이는 매우 중요합니다.

Google 양식을 통해 이벤트에 등록하고 이름, 이메일, 주소, 전화번호 및 기타 개인 정보와 같은 세부 정보를 웹페이지에 입력한다고 가정해 보세요. 웹사이트/앱이 GET 메서드를 사용하여 등록 요청을 보내거나 다른 인증/개인 정보 보호 관련 요청을 수행하는 경우 URL 자체에 데이터가 노출될 수 있습니다. 사용자가 악의적으로 네트워크에 침투하여 URL을 검사하는 경우 https://form.google.com/register/-/?name=John&phone_number=1234567890과 같은 내용일 수 있습니다. , 귀하의 데이터가 노출됩니다. 이것이 바로 POST 메소드가 필요한 이유입니다.

POST 메서드는 어떻게 작동하나요?

POST 요청은 리소스를 생성하거나 업데이트(업데이트하는 방법은 별도로 있음)하기 위해 서버에 데이터를 보내는 데 사용됩니다. 클라이언트(브라우저/기타 API)는 요청 본문의 데이터와 함께 서버의 API 엔드포인트에 POST 요청을 보냅니다. 이 데이터는 JSON, XML 또는 양식 데이터와 같은 형식일 수 있습니다. 서버는 POST 요청을 처리하고, 요청 본문의 데이터를 검증 및 구문 분석하고, 해당 데이터를 기반으로 리소스를 변경하거나 생성하고, 응답을 반환합니다. 응답에는 작업의 성공 또는 실패를 나타내는 상태 코드가 포함되며 응답 본문에 새로 생성되거나 업데이트된 리소스가 포함될 수 있습니다. 클라이언트는 응답 상태 코드를 확인하여 결과를 확인하고 이에 따라 응답을 처리해야 합니다. GET과 달리 POST는 서버에 새 리소스를 생성할 수 있습니다. POST의 본문에는 생성할 데이터가 포함되어 있고 URL은 생성될 리소스를 식별합니다. 전반적으로 POST는 리소스 처리, 생성 또는 업데이트를 위해 데이터를 서버로 전송합니다.

상태 코드는 일반적으로 리소스가 성공적으로 생성되었음을 나타내는 201이거나 단지 성공을 나타내는 경우 200입니다.

개발자가 POST 요청을 생성하고 보내는 일반적인 단계는 다음과 같습니다.

  • API 엔드포인트 정의

  • 데이터 형식 명확화(json, 언어 기본 개체, xml, 텍스트, 양식 데이터 등)

  • 데이터 변환/마샬링

  • Content-Type에 대한 헤더를 키로, 값을 데이터 유형의 형식으로 첨부(예: json의 경우 application/json)

  • 요청 보내기

위 단계는 POST 요청을 생성하고 보내는 일반적인 단계이며 Golang에만 국한되지 않습니다. golang의 특정 단계를 위해서는 좀 더 깊이 들어가야 합니다. 시작해 보겠습니다.

Basic POST method in Golang

To send a POST request in golang, we need to use the http package. The http package has the Post method, which takes in 3 parameters, namely the URL, the Content-Type, and the Body. The body can be nil if the URL endpoint doesn't necessarily require a body. The Content-Type is the string, since we are just touching on how the Post request is constructed, we will see what the Content-Type string value should be in the later sections.

http.Post(URL, Content-Type, Body)

package main

import (
    "fmt"
    "net/http"
)

func main() {
    apiURL := "https://reqres.in/api/users"

    // POST request
    resp, err := http.Post(apiURL, "", nil)
    // ideally the Content-Type header should be set to the relevant format
    // resp, err := http.Post(apiURL, "application/json", nil)
    if err != nil {
        panic(err)
    }
    fmt.Println(resp.StatusCode)
    fmt.Println(resp)
    defer resp.Body.Close()
}
$ go run main.go

201                                                               
&{
    201 Created 
    201 
    HTTP/2.0 
    2
    0 
    map[
        Access-Control-Allow-Origin:[*]
        Cf-Cache-Status:[DYNAMIC] 
        Cf-Ray:[861cd9aec8223e4b-BOM] 
        Content-Length:[50] 
        Content-Type:[application/json; charset=utf-8] 
        Date:[Sat, 09 Mar 2024 17:40:28 GMT] 
        Server:[cloudflare] 
        ...
        ...
        ...
        X-Powered-By:[Express]
    ] 
    {0xc00017c180}
    50
    []
    false
    false
    map[]
    0xc000156000
    0xc00012a420
}

The above code is sending the POST request to the https://reqres.in/api/users endpoint with an empty body and no specific format for Content-Type header. The response is according to the Response structure. We can see we got 201 status, which indicates the server received the POST request successfully, the API is a dummy api, so we don't care about the data we are processing, we are just using the API as a placeholder for sending the POST request.

We can use map[string]interface{} it to pass the data in the request body. The json.Marshal method is used to convert the map into JSON format. We will look into the details shortly in the next few examples.

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

func main() {
    apiURL := "https://reqres.in/api/users"
    bodyMap := map[string]interface{}{
        "name": "morpheus",
        "job": "leader",
    }

    requestBody, err := json.Marshal(bodyMap)
    if err != nil {
        panic(err)
    }
    body := bytes.NewBuffer(requestBody)

    resp, err := http.Post(apiURL, "application/json", body)
    if err != nil {
        panic(err)
    }
    fmt.Println(resp.StatusCode)
    defer resp.Body.Close()
}
$ go run main.go

201

The above code sends the POST request to the https://reqres.in/api/users endpoint with the data in the request body in JSON format.

Creating a POST request in Golang

We can construct the POST request with the NewRequest method. The method takes in 3 parameters, namely the method (e.g. POST, GET), the URL and the body (if there is any). We can then add extra information to the headers or the Request object after constructing the basic HTTP Request object.

package main

import (
    "fmt"
    "net/http"
)

func main() {
    apiURL := "https://reqres.in/api/users"

    req, err := http.NewRequest(http.MethodPost, apiURL, nil)
    if err != nil {
        panic(err)
    }
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    fmt.Println(resp.StatusCode)
    //fmt.Println(resp)
    defer resp.Body.Close()
}
$ go run main.go

201

In the above example, we have created an HTTP Request as the POST method, with https://reqres.in/api/users as the URL, and no body. This constructs an HTTP Request object, which can be sent as the parameter to the http.DefaultClient.Do method, which is the default client for the request we sent in the earlier examples as http.Get or http.Post methods. We can implement a custom client as well, and then apply Do the method with the request parameters. The Do method returns the Request object or the error if any.

More on the customizing Client will be explained in a separate post in the series.

The response is also in the same format as the Response structure that we have seen earlier. This section of the series aims to construct a post request, and not to parse the response, we have already understood the parsing of the response in the Get method section of the series.

Parsing objects to JSON for POST method request

We might have a golang object that we want to send as a body to an API in the POST request, for that we need to convert the golang struct object to JSON. We can do this by using the Marshal or the Encode method for serialization of the golang struct object to JSON.

Using Marshal method

Marshaling is the process of converting data from a data structure into a format suitable for transmission over a network or for storage. It's commonly used to convert native objects in a programming language into a serialized format, typically a byte stream, that can be transmitted or stored efficiently. You might get a question here, what is the difference between Marshalling and Serialization? Well, Serialization, is a broader term that encompasses marshalling. It refers to the process of converting an object or data structure into a format that can be stored or transmitted and later reconstructed into the original object. Serialization may involve converting data into byte streams, XML, JSON, or other formats. So, in summary, marshaling specifically deals with converting native objects into a format suitable for transmission, while serialization encompasses the broader process of preparing data for storage or transmission.

The json package has the Marshal method that converts the golang object into JSON. The Marshal method takes in a parameter as the struct object with type any and returns a byte slice []byte and error (if any).

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

type User struct {
    Name   string `json:"name"`
    Salary int    `json:"salary"`
    Age    int    `json:"age"`
}

func main() {
    user := User{
        Name:   "Alice",
        Salary: 50000,
        Age:    25,
    }
    apiURL := "https://dummy.restapiexample.com/api/v1/create"

    // marshalling process
    // converting Go specific data structure/types to JSON
    bodyBytes, err := json.Marshal(user)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(bodyBytes))

    // reading json into a buffer/in-memory
    body := bytes.NewBuffer(bodyBytes)

    // post request
    resp, err := http.Post(apiURL, "application/json", body)
    if err != nil {
        panic(err)
    }
    fmt.Println(resp.StatusCode)
    defer resp.Body.Close()
}
$ go run main.go

{"name":"Alice","salary":50000,"age":25}
200

In the above example, we have created a struct User with fields Name, Salary, and Age, the json tags will help label each key in JSON with the tag for the respective fields in the struct. We create an object user of a type User with the values as Alice, 50000, and 25 respectively.

We call the json.Marshal method with the parameter user that represents the struct object User, the method returns a slice of bytes, or an error either or both could be nil. If we try to see the stringified representation of the byte slice, we can see something like {"name":"Alice","salary":50000,"age":25} which is a JSON string for the user struct. We can't parse the byte slice as the body in the POST request, we need the io.Reader object, so we can load the byte slice bodyBytes into a buffer and parse that as a body for the POST request.

We then send a POST request to the endpoint https://dummy.restapiexample.com/api/v1/create with the content type as application/json and with the body as body which was a io.Reader object as an in-memory buffer.

In brief, we can summarize the marshaling of the golang object into JSON with Marshal function as the following steps:

  • Defining the structure as per the request body

  • Creating the struct object for parsing the data as body to the request

  • Calling the json.Marshal function to convert the object to JSON (parameter as the struct object any type)

  • Loading the byte slice into a buffer with bytes.NewBuffer()

  • Sending the POST request to the endpoint with the body as the io.Reader object and content type as application/json

Using Encode method

We can even use the Encoder.Encode method to parse the golang struct object to JSON. Firstly, we should have the struct defined as per the request body that the particular API takes, we can make use of the json tags, omitempty, omit(-) options to make the marshaling process work accordingly. We can then create the object of that particular struct with the data we require to be created as a resource with the POST request on that API service.

Thereafter we can create an empty buffer object with bytes.Buffer, this buffer object would be used to initialize the Encoder object with the NewEncoder method. This would give access to the Encode method, which is used to take in the struct object (any type) and this will populate the buffer we initialized with the NewEncoder method.

Later we can access that buffer to parse it to the Post request as the body. Let's understand it better with an example.

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

type User struct {
    Name   string
    Salary int
    Age    int
}

func main() {
    user := User{
        Name:   "Alice",
        Salary: 50000,
        Age:    25,
    }
    apiURL := "https://dummy.restapiexample.com/api/v1/create"

    var bodyBuffer bytes.Buffer
    var encoder = json.NewEncoder(&bodyBuffer)
    err := encoder.Encode(user)
    if err != nil {
        panic(err)
    }

    resp, err := http.Post(apiURL, "application/json", &bodyBuffer)
    if err != nil {
        panic(err)
    }
    fmt.Println(resp.StatusCode)
    fmt.Println(resp)
    defer resp.Body.Close()
}

Over here, we have created a struct User with fields Name, Salary, and Age, we initialize the user as the object of the User struct. Then we create a buffer bodyBuffer of type bytes.Buffer this is the actual buffer that we will send as the body. Further, we initialize the Encoder object as encoder with the json.NewEncoder method by parsing the reference of bodyBuffer as the parameter. Since bytes.Buffer implements the io.Writer interface, we can pass the bodyBuffer to the NewEncoder method. This will create the Encoder object which in turn will give us access to the Encode method, where we will parse the struct instance and it will populate the buffer with which we initialized the Encoder object earlier.

Now, we have the encode object, this gives us the access to Encode method, we call the Encode method with the parameter of user which is a User struct instance/object. The Encode method will populate the bodyBuffer object or it will result in an error if anything goes wrong (the data is incorrectly parsed or is not in the required format).

We can call the Post method with the initialized URL, the Content-Type as application/json since we have converted the struct instance to JSON object, and the body as the reference to the buffer as &bodyBuffer

So, the steps for parsing struct instances into JSON objects with the Encoder.Encode method is as follows:

  • Defining the structure as per the request body

  • Creating the struct object for parsing the data as body to the request

  • Creating an empty bytes.Buffer object as an in-memory buffer

  • Initializing the Encoder object with NewEncoder method by parsing the reference of bodyBuffer as the parameter

  • Calling the Encode method with the parameter of struct instance/object

  • Sending the POST request to the endpoint with the content type as application/json and body as the reference to the buffer

The results are the same as the above example just the way we have parsed the struct instance to JSON object is different.

Parsing JSON to POST request

We have seen how we can parse golang struct instances to JSON and then send the post request, but what if we had the JSON string already with us, and we want to send the request? Well, that's much easier, right? We already have parsed the JSON string to the Post request by loading the slice of bytes into a buffer, so we just need to convert the string to a slice of bytes which is quite an easy task, and then load that byte slice to the buffer.

package main

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

func main() {
    // dummy api
    apiURL := "https://dummy.restapiexample.com/api/v1/create"

    // json data
    data := `{
        "name": "Alice",
        "job": "Teacher"
    }`
    body := bytes.NewBuffer([]byte(data))

    // POST request
    resp, err := http.Post(apiURL, "application/json", body)
    if err != nil {
        panic(err)
    }
    fmt.Println(resp.StatusCode)
    fmt.Println(resp)
    defer resp.Body.Close()
}

In the example above, we already have a JSON string data with keys as name and job but it is not JSON, it is a stringified JSON. We can convert the stringified JSON to a slice of bytes using the []byte function. Further, we have used the bytes.NewBuffer method to load the byte slice into an io.Reader object. This object returned by the bytes.NewBuffer will serve as the body for the POST request.

Parsing JSON to objects in Golang from POST method response

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

type User struct {
    Name   string `json:"name"`
    Salary int    `json:"salary"`
    Age    string `json:"age"`
    ID     int    `json:"id,omitempty"`
}

type UserResponse struct {
    Status string `json:"status"`
    Data   User   `json:"data"`
}

func main() {
    user := User{
        Name:   "Alice",
        Salary: 50000,
        Age:    "25",
    }
    apiURL := "https://dummy.restapiexample.com/api/v1/create"

    // marshalling process
    // converting Go specific data structure/types to JSON
    bodyBytes, err := json.Marshal(user)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(bodyBytes))

    // reading json into a buffer/in-memory
    body := bytes.NewBuffer(bodyBytes)

    // post request
    resp, err := http.Post(apiURL, "application/json", body)
    if err != nil {
        panic(err)
    }
    fmt.Println(resp.StatusCode)
    fmt.Println(resp)
    defer resp.Body.Close()

    // Read response body
    respBody, err := io.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }

    // unmarshalling process
    // converting JSON to Go specific data structure/types
    var userResponse UserResponse
    if err := json.Unmarshal(respBody, &userResponse); err != nil {
        panic(err)
    }
    fmt.Println(userResponse)
    fmt.Println(userResponse.Data)
}
{success {Alice 50000 25 3239}}
{Alice 50000 25 577}

The above example is a POST request with a struct instance being loaded as a JSON string and then sent as a buffer to the API endpoint, it also reads the response body with a specific structure UserResponse and unmarshalled the resp.Body from the io.Reader as respBody and then loads into userResponse object. This example gives an entire process of what we have understood in the JSON data parsing for a POST request.

Sending Form data in a POST request

We can also send data to a POST request in the form of a form, the form which we use in the HTML. Golang has a net/url package to parse the form data. The form data is sent in the application/x-www-form-urlencoded format.

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "strings"
)

type ResponseLogin struct {
    Token string `json:"token"`
}

func main() {
    // dummy api
    apiURL := "https://reqres.in/api/login"

    // Define form data
    formData := url.Values{}
    formData.Set("email", "eve.holt@reqres.in")
    formData.Set("password", "cityslicka")

    // Encode the form data
    fmt.Println(formData.Encode())
    reqBody := strings.NewReader(formData.Encode())
    fmt.Println(reqBody)

    // Make a POST request with form data
    resp, err := http.Post(apiURL, "application/x-www-form-urlencoded", reqBody)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    // Print response status code
    fmt.Println("Status Code:", resp.StatusCode)

    // Read response body
    respBody, err := io.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }
    token := ResponseLogin{}

    json.Unmarshal(respBody, &token)
    fmt.Println(token)
}
$ go run main.go

email=eve.holt%40reqres.in&password=cityslicka
&{email=eve.holt%40reqres.in&password=cityslicka 0 -1}
Status Code: 200
{QpwL5tke4Pnpja7X4}

In the above example, we set a formData with the values of email and password which are url.Values object. The url.Values the object is used to store the key-value pairs of the form data. The formData is encoded with the url.Encode method, We load the encoded string to a buffer with strings.NewReader which implements the io.Reader interface, so that way we can pass that object as the body to the post request.

We send the POST request to the endpoint https://reqres.in/api/login with the content type as application/x-www-form-urlencoded and with the body as reqBody which implements the io.Reader interface as an in-memory buffer. The response from the request is read into the buffer with io.ReadAll method and we can Unmarshal the stream of bytes as a buffer into the ResponseLogin struct object.

The output shows the formData as encoded string email=eve.holt%40reqres.in&password=cityslicka as @ is encoded to %40, then we wrap the formData in a strings.NewReader object which is a buffer that implements io.Reader interface, hence we can see the result as the object. The status code for the request is 200 indicating the server received the form-data in the body and upon unmarshalling, we get the token as a response to the POST request which was a dummy login API.

This way we have parsed the form-data to the body of a POST request.

Sending File in a POST request

We have covered, parsing text, JSON, and form data, and now we need to move into sending files in a POST request. We can use the multipart package to parse files into the request body and set appropriate headers for reading the file from the API services.

We first read the file contents os.Open which returns a reference to the file object or an error. We create an empty bytes.Buffer object as body which will be populated later. The multipart.NewWriter method takes in the io.Writer object which will be the body as it is an bytes.Buffer object that implements the io.Writer interface. This will initialize the Writer object in the multipart package.

We create a form-field in the Writer object with the CreateFormFile method, which takes in the fieldName as the name of the field, and the fileName as the name of the file which will be read later in the multipart form. The method returns either the part or the error. The part is an object that implements the io.Writer interface.

Since we have stored the file contents in the file object, we copy the contents into the form-field with the Copy method. Since the part return from the CreateFormFile was implementing the io.Writer interface, we can use it to Copy the contents from source to destination. The source is the io.Reader object and the destination is the io.Writer object, the destination for the Copy method is the first parameter, the source is the second parameter.

This Copy method will populate the buffer initialized earlier in the NewWriter method. This will give us a buffer that has the file contents in it. We can pass this buffer to the POST request with the body parameter. We also need to make sure we close the Writer object after copying the contents of the file. We can extract the type of file which will serve as the Content-Type of the request.

Let's clear the explanation with an example.

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "mime/multipart"
    "net/http"
    "os"
)

type ResponseFile struct {
    Files map[string]string `json:"files"`
}

func main() {
    apiURL := "http://postman-echo.com/post"
    fileName := "sample.csv"

    file, err := os.Open(fileName)
    if err != nil {
        panic(err)
    }
    defer file.Close()

    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)

    part, err := writer.CreateFormFile("csvFile", fileName)
    if err != nil {
        panic(err)
    }
    _, err = io.Copy(part, file)
    if err != nil {
        panic(err)
    }

    contentType := writer.FormDataContentType()
    fmt.Println(contentType)

    writer.Close()

    resp, err := http.Post(apiURL, contentType, body)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println("Status Code:", resp.StatusCode)

    respBody, err := io.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }
    token := ResponseFile{}
    json.Unmarshal(respBody, &token)
    fmt.Println(token)
    fmt.Println(token.Files[fileName])
}
multipart/form-data; boundary=7e0eacfff890be395eba19c70415c908124b503a56f23ebeec0ab3c665ca


--619671ea2c0aa47ca6664a7cda422169d73f3b8a089c659203f5413d03de
Content-Disposition: form-data; name="csvFile"; filename="sample.csv"
Content-Type: application/octet-stream

User,City,Age,Country
Alex Smith,Los Angeles,20,USA
John Doe,New York,30,USA
Jane Smith,Paris,25,France
Bob Johnson,London,40,UK

--619671ea2c0aa47ca6664a7cda422169d73f3b8a089c659203f5413d03de--



Status Code: 200

{map[sample.csv:data:application/octet-stream;base64,VXNlcixDaXR5LEFnZSxDb3VudHJ5CkFsZXggU21pdGgsTG9zIEFuZ2VsZXMsMjAsVVNBCkpvaG4gRG9lLE5ldyBZb3JrLDMwLFVTQQpKYW5lIFNtaXRoLFBhmlzLDI1LEZyYW5jZQpCb2IgSm9obnNvbixMb25kb24sNDAsVUsK]}

data:application/octet-stream;base64,VXNlcixDaXR5LEFnZSxDb3VudHJ5CkFsZXggU21pdGgsTG9zIEFuZ2VsZXMsMjAsVVNBCkpvaG4gRG9lLE5ldyBZb3JrLDMwLFVTQQpKYW5lIFNtaXRoLFBhmlzLDI1LEZyYW5jZQpCb2IgSm9obnNvbixMb25kb24sNDAsVUsK

In the above example, we first read the file sample.csv into the file object with os.Open method, this will return a reference to the file object or return an error if any arises while opening the file.

Then we create an empty buffer bytes.Buffer object which will serve as the body of the post request later as it will get populated with the file contents in the form of multipart/form-data.

We initialize the Writer object with multipart.NewWriter method which takes in the empty buffer as the parameter, we parse the body as the parameter. The method will return a reference to the multipart.Writer object.

With the Writer object we access the CreateFormFile method which takes in the fieldName as the name of the field, and the fileName as the name of the file. The method will return either the part or an error. The part in this case, is the reference to the io.Writer object that will be used to write the contents from the uploaded file.

Then, we can use the io.Copy method to copy the contents from the io.Reader object to the io.Writer object. The source is the io.Reader object and the destination is the io.Writer object. The first parameter is however the destination and the second parameter is the source. In the example, we call io.Copy(part, file) which will copy the contents of file to the part buffer.

We get the Content-Type by calling the Writer.FormDataContentType method. This returns us multipart/form-data; boundary=7e0eacfff890be395eba19c70415c908124b503a56f23ebeec0ab3c665ca which will serve the Content-Type for the Post request.

We need to make sure we close the Writer object with the Close method.

We just print the body.String() to get a look at what the actual body looks like, we can see there is a form for the file as a form-data with keys like Content-Type, Content-Disposition, etc. The file has the Content-Type as application/octet-stream and the actual content is rendered in the output.

The dummy API responds with a 200 status code and also sends the JSON data with the name of the file as the key and the value as the base64 encoded value of the file contents. This indicates that we were able to upload the file to the server API using a POST request. Well done!

I have also included some more examples of POST requests with files here which extends the above example by taking the encoded values and decoding to get the actual contents of the file back.

Best Practices for POST method

Here are some of the best practices for the POST method which are followed to make sure you consume or create the POST request in the most secure, efficient, and graceful way.

Always Close the Response Body

Ensure that you close the response body after reading from it. Use defer response.Body.Close() to automatically close the body when the surrounding function returns. This is crucial for releasing associated resources like network connections or file descriptors. Failure to close the response body can lead to memory leaks, particularly with a large volume of requests. Properly closing the body prevents resource exhaustion and maintains efficient memory usage.

Client Customization

Utilize the Client struct to customize the HTTP client behavior. By using a custom client, you can set timeouts, headers, user agents, and other configurations without modifying the DefaultClient provided by the http package. This approach allows for flexibility and avoids repetitive adjustments to the client configuration for each request.

Set Content-Type Appropriately

Ensure that you set the Content-Type header according to the request payload. Correctly specifying the Content-Type is crucial for the server to interpret the request payload correctly. Failing to set the Content-Type header accurately may result in the server rejecting the request. Always verify and match the Content-Type header with the content being sent in the POST request to ensure smooth communication with the server.

That's it from the 34th part of the series, all the source code for the examples are linked in the GitHub on the 100 days of Golang repository.

Golang Web: POST Method 미스터 파괴자 / 100일의 골랑

100일간의 golang 시리즈에 대한 스크립트 및 리소스(진행 중)

고랑 100일

Go lang은 작성하기 쉽고 유형 및 메모리 안전성, 가비지 수집 및 구조적 유형 지정 기능까지 제공하는 프로그래밍 언어입니다. 2009년 Google 팀에 의해 개발되었으며 2012년에 오픈 소스로 제공되었습니다. 클라우드 네이티브 기술 및 웹 애플리케이션용으로 만들어진 프로그래밍 언어입니다. 범용 프로그래밍 언어이므로 만들고 싶은 프로그램 유형에 제한이 없습니다.

  • 공식 홈페이지
  • GitHub 저장소
  • 표준도서관
  • 패키지 가기
  • 멋진 Go 프로젝트와 프레임워크

Golang 학습 자료

  • 운동-트랙타기
  • 예를 들어보세요
  • Go Time - 팟캐스트
  • Boot.dev Golang 강좌
  • Zetcode 블로그
  • daily.dev Golang 기사

GO!로 만든 유명 애플리케이션



















Web apps DevOps tools CLI tools

SoundCloud - Music System

Prometheus - Monitoring system and time series database

gh-cli - Official Github CLI

Uber - Ride Sharing/Cab booking Webapp


GitHub에서 보기


참조

  • Postman POST API(파일 업로드를 통한 POST 요청용)

  • Golang net/http 패키지

결론

이번 시리즈 게시물, golang의 POST 메서드에 대한 게시물입니다 :)

기본 게시물 요청 생성, golang 유형을 JSON 형식으로 마샬링, 양식 데이터 구문 분석, 파일과 함께 POST 요청 보내기, POST 메서드 모범 사례 등의 주제를 다루었습니다. 이 기사가 도움이 되었기를 바랍니다. 질문이나 피드백이 있으시면 댓글이나 소셜 계정을 통해 알려주시기 바랍니다.

행복한 코딩하세요 :)

위 내용은 Golang 웹: POST 메서드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.