정리 기능이 있는 바닐라 Go의 실용적인 웹 서버

25036 단어 gohelpbeginners
그래서 webview/webview 에 맞추기 위해 Golang에서 웹 서버를 작성하려고 했지만 현재 an important issue (cgo ) ...

내가 정말로 이해하지 못하는 Go 언어 관련 개념이 있습니다.
  • 채널
  • <-

  • 신호가 POSIX가 아닌 Windows에서 작동합니까?

    그리고 내가 싫어하는 것이 분명히 있습니다 ...

    // Scoping of error variables.
    // Is there a better naming conventions?
    // IMO, these kind of namings are very typo-prone.
    _, e1 := f1()
    if e1 != nil {
      log.Fatal(e1)
    }
    data, e2 := f1()
    if e2 != nil {
      log.Fatal(e2)
    }
    


    요컨대, 그러나 산업과 고용 시장이 그것을 요구합니다.

    아직 JSON 직렬화/역직렬화를 수행하지 않았습니다. 미들웨어와 인증은 말할 것도 없습니다. 그러나 나는 커버한다.
  • req.Query
  • req.Body
  • res.Write
  • 상태 코드

  • package main
    
    import (
        "context"
        "fmt"
        "io/ioutil"
        "log"
        "net"
        "net/http"
        "os"
        "os/signal"
        "syscall"
        "time"
    )
    
    func main() {
        port := os.Getenv("PORT")
        if port == "" {
            port = "0"
        }
    
        listener, err := net.Listen("tcp", "localhost:"+port)
        if err != nil {
            log.Fatal(err)
        }
    
        http.Handle("/", http.FileServer(http.Dir("./dist")))
        http.HandleFunc("/api/file", func(w http.ResponseWriter, r *http.Request) {
            f := r.URL.Query()["filename"]
            if len(f) == 0 {
                throwHTTP(&w, fmt.Errorf("filename not supplied"), http.StatusNotFound)
                return
            }
            filename := f[0]
    
            if r.Method == "GET" {
                data, eReadFile := ioutil.ReadFile(filename)
                if eReadFile != nil {
                    throwHTTP(&w, eReadFile, http.StatusInternalServerError)
                    return
                }
                w.Write(data)
                return
            } else if r.Method == "PUT" {
                data, eReadAll := ioutil.ReadAll(r.Body)
                if eReadAll != nil {
                    throwHTTP(&w, eReadAll, http.StatusInternalServerError)
                    return
                }
                eWriteFile := ioutil.WriteFile(filename, data, 0666)
                if eWriteFile != nil {
                    throwHTTP(&w, eWriteFile, http.StatusInternalServerError)
                    return
                }
                w.WriteHeader(http.StatusCreated)
                return
            } else if r.Method == "DELETE" {
                eRemove := os.Remove(filename)
                if eRemove != nil {
                    throwHTTP(&w, eRemove, http.StatusInternalServerError)
                    return
                }
                w.WriteHeader(http.StatusCreated)
                return
            }
    
            throwHTTP(&w, fmt.Errorf("unsupported method"), http.StatusNotFound)
        })
    
        go func() {
            // True port will be autogenerated
            // And Addr() generated accordingly
            log.Println("Listening at:", "http://"+listener.Addr().String())
            if err := http.Serve(listener, nil); err != http.ErrServerClosed {
                log.Fatal(err)
            }
        }()
    
        // Cleaning up should be done in 10 seconds
        onExit(10 * time.Second)
    }
    
    func onExit(timeout time.Duration) {
        signals := make(chan os.Signal, 1)
        signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
    
        <-signals
    
        log.Println("Cleaning up...")
    
        ctx, cancel := context.WithTimeout(context.Background(), timeout)
        defer cancel()
    
        // onExit proper
        func() {
            time.Sleep(2 * time.Second)
        }()
    
        if _, ok := ctx.Deadline(); ok {
            log.Println("Clean-up finished. Closing...")
            // secs := (time.Until(deadline) + time.Second/2) / time.Second
            // log.Printf("Clean-up finished %ds before deadline\n", secs)
        } else {
            log.Fatal(fmt.Sprintf("Clean-up timeout. Not finished within %ds.", timeout/time.Second))
        }
    }
    
    func throwHTTP(w *http.ResponseWriter, e error, code int) {
        http.Error(*w, e.Error(), code)
        log.Println(e, code)
    }
    


    cURL로 테스트됨

    % PORT=3000 go run .
    % curl -i -X PUT --data 'hello' http://127.0.0.1:3000/api/file\?filename\=test.txt
    


    프론트엔드와 연결하는 또 다른 좋은 방법이 있습니다. SQL과 그 매개변수를 보내는 것이 더 나은 방법일 수 있다고 주장할 수 있습니다.

    import Loki from 'lokijs'
    
    class LokiRestAdaptor {
      loadDatabase (dbname: string, callback: (data: string | null | Error) => void) {
        fetch(`/api/file?filename=${encodeURIComponent(dbname)}`)
          .then((r) => r.text())
          .then((r) => callback(r))
          .catch((e) => callback(e))
      }
    
      saveDatabase (dbname: string, dbstring: string, callback: (e: Error | null) => void) {
        fetch(`/api/file?filename=${encodeURIComponent(dbname)}`, {
          method: 'PUT',
          body: dbstring
        })
          .then(() => callback(null))
          .catch((e) => callback(e))
      }
    
      deleteDatabase (dbname: string, callback: (data: Error | null) => void) {
        fetch(`/api/file?filename=${encodeURIComponent(dbname)}`, {
          method: 'DELETE'
        })
          .then(() => callback(null))
          .catch((e) => callback(e))
      }
    }
    
    // eslint-disable-next-line import/no-mutable-exports
    export let loki: Loki
    
    export async function initDatabase () {
      return new Promise((resolve) => {
        loki = new Loki('db.loki', {
          adapter: new LokiRestAdaptor(),
          autoload: true,
          autoloadCallback: () => {
            resolve()
          },
          autosave: true,
          autosaveInterval: 4000
        })
      })
    }
    
    

    좋은 웹페이지 즐겨찾기