2022년 11월 18일 금요일

Golang_tip_ebook_kth

Golang_tip_ebook_kth

수시로 업데이트 중…

Go Style Guide

https://google.github.io/styleguide/go/guide

Effective Go

https://go.dev/doc/effective_go

network

net/http 패키지를 이용한 웹서버 제작

golang에서 기본적으로 제공하는 net/http패키지를 이용해서 웹서버를 구축할수 있다. 일단 얼마나 간단한지 보자.

1.초간단 서버 구동

package main

import (
   "fmt"
   "net/http"
)

func main() {
   http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
       fmt.Fprintln(w, r.Method, "welcome Go lang")
   })
   http.ListenAndServe(":8080", nil)
}

/* 
or 
import "log"
fun printHello(w http.ResponseWriter, r *http.Request) {
       fmt.Fprintln(w, r.Method, "welcome Go lang"
}
func main() {
   http.HandleFunc("/", printHello)
   if err := http.ListenAndServe(":8000", nil); err != nil {
        log.Fatal("ListenAndServe: ", err)
    }

}

*/

웹서버를 구동할수 있는 net/http 패키지를 제공하기 때문에 단 몇줄만으로도 웹서버를 구동하여 응답문자와 접속메소드를 출력할수 있다.

간단한 echo(응답) 서버이지만 , 여러개의 endpoint를 생성한다면 간단한 API서버를 금방 만들수 있다.

API서버는 여러개의 endpoint를 가지는데 다루기쉬운 Restful(패스파라메터와 요청파라메터로 구성된) 방식으로 만들기 위해서는 Router라는 것을 만들어 사용자가 요청한 페이지와 파라메터에 맞게 적절한 응답을 해주어야 한다.

  1. net/http
    net / http 패키지는 HTTP 클라이언트와 HTTP 서버를 구현하는 데 필요한 기능을 제공하고 있다.
  2. http.ListenANdServe
    서버를 기동 시겨준다.
  3. HandlerFunc
    golang에서 제공하는 기본적인 주소매칭방식인 DefaultServeMux 으로 url주소패턴과 실행될 함수를 지정한다.
    두번째 인자로 handler 를 받게 되는데 이곳에서 응답처리와 클라이언트로부터의 요청에 대한 처리를 수행한다.

    pattern : url 패턴이다
    handler : Reponse(응답) 과 Request(요청된것) 을 인자로 받는 함수이다.
  4. Handle
    HandlerFunc 는 항상 지정된 같은 함수의 루틴일 실행하게 되는데, 같은 url패턴이라도 상황에 따라, 예를들면 로그인전/후의 메인페이지 등과 같이 다른 내용을 보여야 할떄가 있다. 이럴때는 처리해서 보여줄 페이지를 동적으로 구성해야 하는데 Handle 함수의 두번째 인자에 ServerHttp 메소드를 가진 구조체를 지정해주면 된다.
package main

import (
   "fmt"
   "net/http"
)

type RessonseMessage string

func (s RessonseMessage) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   fmt.Fprint(w, s)
}
func main() {
   helloServer := RessonseMessage("hi. there")

   http.Handle("/", helloServer)
   http.ListenAndServe(":8000", nil)
}

2.경로에 따라서 다르게 응답하는 서버

net/http로 요청에 응답을 하는 방식은 HandleFunc 또는 Handle 함수에 두번쨰 인자로 함수를 건네주면된다.

함수를 인터페이스 형식으로 건네주고 싶을 때는 type을 사용한다.
https://github.com/sugoigroup/study_golang/tree/http

type fooHandler struct{}

func Runserver() {

     mux := http.NewServeMux()
     mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "Hello World")
     })

     mux.Handle("/foo", &fooHandler{})

     http.ListenAndServe(":3000", mux)

}

func (f *fooHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  fmt.Fprint(w, strutils.ToUpperCase("Hello Foo!"))
}

3.url 에 입력된 파라메터를 읽기

보통 url에 파라메터를 붙여 서버에 어떤 값을 전송한다. 간단히 url query에서 값을 가져와보자. 간단하다.

func Runserver() {
     mux := http.NewServeMux()
     mux.HandleFunc("/bar", barHandler)
     http.ListenAndServe(":3000", mux)
}

func barHandler(w http.ResponseWriter, r *http.Request) {
  name := r.URL.Query().Get("name")
  if name == "" {
     name = "world"
  }
  fmt.Fprintf(w, "Hello %s!", name)
}

4.응답을 html 로 하기

보통 url에 파라메터를 붙여 서버에 어떤 값을 전송한다. 간단히 url query에서 값을 가져와보자. 간단하다.

func Runserver() {

     mux := http.NewServeMux()
     mux.HandleFunc("/bar", barHandler)
     http.ListenAndServe(":3000", mux)

}

func barHandler(w http.ResponseWriter, r *http.Request) {
  name := r.URL.Query().Get("name")
  if name == "" {
     name = "world"
  }
  w.Header().Set("Content-Type", "text/html") // HTML 헤더 설정
  w.Write(htmlMessage(name))
}

func htmlMessage(msg string) []byte {
  // HTML로 웹 페이지 작성
  html := `
  <html>
  <head>
     <title>Hello</title>
  </head>
  <body>
     <div style='text-align:center'><b>Hello ` + msg + `</b></div>
  </body>
  </html>
  `
  return []byte(html)
}

5. json 요청받아서 json 형태로 출력하기 으로 하기

API서버에서 자주 쓰이는 Json형식으로 request받아서 Json형식으로 response해보자.
받아올 json은 struct형태로 정의해서 golang의 기본 패키지인 encoding/json을 이용하면 쉽게 인코딩,디코딩 할수 있다 . 할수있다.
struct를 json형식으로 이용하기 위해서는 몇가지 규칙이 있다.

  • 구조체필드 이름의 첫글자를 대문자로 하여야 외부에 공개되어 json 문장에서 매치되어 값이 할당된다.
  • 프로그램상의 필드이름형식과 json의 키형식이 다를경우 json:"키이름" 와 같이 하여 준다. (FirstName string json:"first_name")

golang 에서 json인코딩/디코딩을 해주는 함수는 기본적으로 다음과 같다.

  • func Marshal(v interface{}) ([]byte, error): Go 언어 자료형(구조체 또는 맵)를 JSON 텍스트로 변환한다.
  • func Unmarshal(data []byte, v interface{}) error: JSON 텍스트를 Go 언어 자료형(구조체 또는 맵)으로 변환
  
import (  
  "encoding/json"  
"fmt" "net/http" "time")
 
 
type User struct {  
  FirstName string `json:"first_name"`  
 LastName string `json:"last_name"`  
 EmailAddress string `json:"email"`  
 CreatedAt time.Time `json:"created_at"`  
}  
 
type fooJsonHandler struct{}  
 
func RunJsonServer() {  
 
  mux := http.NewServeMux()  
  mux.Handle("/api/myjson", &fooJsonHandler{})  
 
  http.ListenAndServe(":3000", mux)  
}  
 
 
func (f *fooJsonHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {  
  user := new(User)  
  err := json.NewDecoder(r.Body).Decode(user)  
  print(err)  
  if err != nil {  
     w.WriteHeader(http.StatusBadRequest)  
     fmt.Fprint(w, "json format error", err)  
     return  
 }  
  user.CreatedAt = time.Now()  
 
  data, _ := json.Marshal(user)  
  w.Header().Add("content-type", "application/json")  
  w.WriteHeader(http.StatusCreated)  
  fmt.Fprint(w, string(data))
  /*
request body
{
 "first_name": "kim",
 "last_name": "tae",
 "email": "test@test.com"
}

response 
{
"first_name": "kim",
"last_name": "tae",
"email": "test@test.com",
"created_at": "2021-03-28T23:41:20.531437+09:00"
}
  */

File I/O

1.1 파일을 열고 defer 로 함수끝에 닫기

// Open test midi file
file, err := os.Open("./Test_-_test1.mid")
if err != nil {
	log.Fatal(err)
}
defer file.Close()

https://godoc.org/github.com/gophersjp/go/src/os

ETC

scanf 로 콘솔 입력받기

fmt.Println(“Please enter your name.”)
var name string
fmt.Scanln(&name)
fmt.Printf("Hi, %s! ", name)

0 comments:

댓글 쓰기