HTTP 요청과 응답에서 Content-Type 헤더는 전송되는 데이터의 형식을 정의하며, 클라이언트와 서버 간 데이터 처리 방식을 결정합니다. 각 Content-Type은 특정 데이터 형식에 맞춰 처리되며, 다양한 데이터 전송 방식에 맞춰 사용됩니다.



1. Content-Type별 패킷 바디 구조


(1) text/plain

  • 설명: 단순 텍스트 데이터를 전송할 때 사용됩니다.
  • 바디 예시: Hello, this is plain text!

(2) application/x-www-form-urlencoded

  • 설명: URL 인코딩된 키-값 쌍을 전송할 때 사용됩니다. 주로 HTML 폼 데이터 전송에 사용됩니다.
  • 바디 예시: key1=value1&key2=value2

(3) application/json

  • 설명: JSON 형식의 데이터를 전송할 때 사용됩니다.
  • 바디 예시: json { "key1": "value1", "key2": "value2" }

(4) multipart/form-data

  • 설명: 여러 부분으로 나뉘어진 데이터를 전송할 때 사용됩니다. 주로 파일 업로드에 사용됩니다.
  • 바디 예시:
--boundary123
    Content-Disposition: form-data; name="key1"

    value1
--boundary123
    Content-Disposition: form-data; name="file"; filename="example.txt"
    Content-Type: text/plain

    File content here.
--boundary123--




2. Go에서 http/net 및 Gin으로 요청/응답 처리


(1) text/plain

요청(Request) 생성

  • http/net:
    package main

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

    func main() {
        body := []byte("Hello, this is plain text!")
        req, err := http.NewRequest("POST", "<http://example.com>", bytes.NewBuffer(body))
        if err != nil {
            log.Fatal(err)
        }
        req.Header.Set("Content-Type", "text/plain")

        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {
            log.Fatal(err)
        }
        defer resp.Body.Close()
    }

  • Gin:
 package main

 import (
     "github.com/gin-gonic/gin"
 )

 func main() {
     r := gin.Default()
     r.POST("/text", func(c *gin.Context) {
         body, _ := c.GetRawData()
         c.String(200, "Received: %s", string(body))
     })
     r.Run(":8080")
 }


(2) application/x-www-form-urlencoded

요청(Request) 생성

  • http/net:
package main

import (
	"bytes"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	var requestBody bytes.Buffer
	writer := multipart.NewWriter(&requestBody)

	err := writer.WriteField("key1", "value1")
	if err != nil {
		log.Fatal(err)
	}

	file, err := os.Open("example.txt") // 실제 파일 열기
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	fileWriter, err := writer.CreateFormFile("file", "example.txt")
	if err != nil {
		log.Fatal(err)
	}

	_, err = io.Copy(fileWriter, file)
	if err != nil {
		log.Fatal(err)
	}

	writer.Close()

	req, err := http.NewRequest("POST", "http://example.com", &requestBody)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
}
  • Gin:
 package main

 import (
     "github.com/gin-gonic/gin"
 )

 func main() {
     r := gin.Default()
     r.POST("/form", func(c *gin.Context) {
         key1 := c.PostForm("key1")
         key2 := c.PostForm("key2")
         c.JSON(200, gin.H{
             "key1": key1,
             "key2": key2,
         })
     })
     r.Run(":8080")
 }


(3) application/json

요청(Request) 생성

  • http/net:
 package main

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

 func main() {
     data := map[string]string{"key1": "value1", "key2": "value2"}
     jsonData, err := json.Marshal(data)
     if err != nil {
         log.Fatal(err)
     }

     req, err := http.NewRequest("POST", "<http://example.com>", bytes.NewBuffer(jsonData))
     if err != nil {
         log.Fatal(err)
     }
     req.Header.Set("Content-Type", "application/json")

     client := &http.Client{}
     resp, err := client.Do(req)
     if err != nil {
         log.Fatal(err)
     }
     defer resp.Body.Close()
 }

  • Gin:
 package main

 import (
     "github.com/gin-gonic/gin"
 )

 func main() {
     r := gin.Default()
     r.POST("/json", func(c *gin.Context) {
         var jsonData map[string]string
         if err := c.ShouldBindJSON(&jsonData); err != nil {
             c.JSON(400, gin.H{"error": err.Error()})
             return
         }
         c.JSON(200, gin.H{
             "key1": jsonData["key1"],
             "key2": jsonData["key2"],
         })
     })
     r.Run(":8080")
 }


(4) multipart/form-data

요청(Request) 생성

  • http/net:
 package main

 import (
     "bytes"
     "mime/multipart"
     "net/http"
     "log"
 )

 func main() {
     var requestBody bytes.Buffer
     writer := multipart.NewWriter(&requestBody)

     _ = writer.WriteField("key1", "value1")
     fileWriter, err := writer.CreateFormFile("file", "example.txt")
     if err != nil {
         log.Fatal(err)
     }
     fileWriter.Write([]byte("File content here"))

     writer.Close()

     req, err := http.NewRequest("POST", "<http://example.com>", &requestBody)
     if err != nil {
         log.Fatal(err)
     }
     req.Header.Set("Content-Type", writer.FormDataContentType())

     client := &http.Client{}
     resp, err := client.Do(req)
     if err != nil {
         log.Fatal(err)
     }
     defer resp.Body.Close()
 }

  • Gin:
 package main

 import (
     "github.com/gin-gonic/gin"
     "net/http"
 )

 func main() {
     r := gin.Default()
     r.POST("/upload", func(c *gin.Context) {
         key1 := c.DefaultPostForm("key1", "default_value")
         file, _ := c.FormFile("file")
         c.String(http.StatusOK, "Received: %s with file %s", key1, file.Filename)
     })
     r.Run(":8080")
 }