рдЧреЛрд▓рдВрдЧ рдореЗрдВ HTTP рд╣реИрдВрдбрд▓рд░реНрд╕ рдХреЗ рд▓реЗрдЦрди рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдПрдВ

рдЖрдиреЗ рд╡рд╛рд▓реЗ HTTP рдЕрдиреБрд░реЛрдз рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддреЗ рд╕рдордп, рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЬреИрд╕реЗ:


  • рдПрдХ рдЖрдиреЗ рд╡рд╛рд▓реА HTTP рдЕрдиреБрд░реЛрдз рд▓реЙрдЧрд┐рдВрдЧ
  • HTTP рд╡рд┐рдзрд┐ рдХреА рдорд╛рдиреНрдпрддрд╛
  • рдкреНрд░рдорд╛рдгреАрдХрд░рдг (рдореВрд▓, рдПрдордПрд╕ рд╡рд┐рдЬреНрдЮрд╛рдкрди, ...)
  • рдЯреЛрдХрди рд╕рддреНрдпрд╛рдкрди (рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ)
  • рдЖрдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреБрд░реЛрдз рдХреЗ рд╢рд░реАрд░ рдХреЛ рдкрдврд╝рдирд╛
  • рдЖрдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреБрд░реЛрдз рдХреЗ рд╣реЗрдбрд░ рдХреЛ рдкрдврд╝рдирд╛
  • рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдиреБрд░реЛрдз рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдЙрддреНрдкрдиреНрди рдХрд░рдирд╛
  • HSTS рд╕рдЦреНрдд-рдкрд░рд┐рд╡рд╣рди-рд╕реБрд░рдХреНрд╖рд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ
  • рдЖрдЙрдЯрдЧреЛрдЗрдВрдЧ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рд╕рд╛рдордЧреНрд░реА-рдкреНрд░рдХрд╛рд░ рд╕реЗрдЯ рдХрд░рдирд╛
  • рдЬрд╛рд╡рдХ HTTP рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд▓реЙрдЧрд┐рдВрдЧ
  • рдЖрдЙрдЯрдЧреЛрдЗрдВрдЧ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд╛ рд░рд┐рдХреЙрд░реНрдб рд╣реЗрдбрд░
  • рд░рд┐рдХреЙрд░реНрдб рдЖрдЙрдЯрдЧреЛрдЗрдВрдЧ рд░рд┐рд╕реНрдкрд╛рдВрд╕ рдмреЙрдбреА
  • рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдФрд░ рд▓реЙрдЧрд┐рдВрдЧ рдореЗрдВ рддреНрд░реБрдЯрд┐
  • рдПрдХ рд╕рдВрднрд╡ рдЖрддрдВрдХ рдХреЗ рдмрд╛рдж рд╡рд╕реВрд▓реА рдХреЗ рд▓рд┐рдП рдбрд┐рдлрд░ рд░рд┐рдХрд╡рд░реА рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ

рдЗрди рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рд╕реЗ рдЕрдзрд┐рдХрд╛рдВрд╢ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╣реИрдВ рдФрд░ рдЕрдиреБрд░реЛрдз рдХреЗ рдкреНрд░рдХрд╛рд░ рдФрд░ рдЗрд╕рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдкрд░ рдирд┐рд░реНрднрд░ рдирд╣реАрдВ рд╣реИрдВред
рдЙрддреНрдкрд╛рджрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреЗ рд▓рд┐рдП, рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреЗ рд▓рд┐рдП рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдФрд░ рд▓реЙрдЧрд┐рдВрдЧ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред


рд╣рд░ HTTP рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рдпрд╣ рд╕рдм рджреЛрд╣рд░рд╛рдирд╛ рдмреЗрд╣рдж рдЕрдХреНрд╖рдо рд╣реИред


рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЕрдЧрд░ рдЖрдк рд╕рднреА рдХреЛрдб рдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЙрдкрдЦрдВрдбреЛрдВ рдореЗрдВ рд░рдЦрддреЗ рд╣реИрдВ, рддреЛ рднреА рдЖрдкрдХреЛ рдЕрдиреБрд░реЛрдз рдХреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рдЧрдарди рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦреЗ рдмрд┐рдирд╛ рдкреНрд░рддреНрдпреЗрдХ HTTP рд╣реИрдВрдбрд▓рд░ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдХреА рд▓рдЧрднрдЧ 80-100 рдкрдВрдХреНрддрд┐рдпрд╛рдВ рдорд┐рд▓рддреА рд╣реИрдВ ред


рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдореИрдВ рдХреЛрдб рдЬрдирд░реЗрдЯрд░ рдФрд░ рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдмрд┐рдирд╛ рдЧреЛрд▓рдВрдЧ рдореЗрдВ HTTP рд╣реИрдВрдбрд▓рд░реНрд╕ рдХреЗ рд▓реЗрдЦрди рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред


backend Golang


.
, , тАФ , - .


HTTP


UML HTTP EchoHandler.


, , :


  • defer . UML тАФ RecoverWrap.func1, .
  • . HTTP handler. UML Process тАФ .
  • HTTP handler. UML EchoHandler.func1 тАФ .

http_handler



.


HTTP EchoHandler, "" .


, EchoHandler, ( RecoverWrap), EchoHandler.


router.HandleFunc("/echo", service.RecoverWrap(http.HandlerFunc(service.EchoHandler))).Methods("GET")

RecoverWrap .
defer func() EchoHandler.


func (s *Service) RecoverWrap(handlerFunc http.HandlerFunc) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        //     
        defer func() {
            var myerr error
            r := recover()
            if r != nil {
                msg := "HTTP Handler recover from panic"
                switch t := r.(type) {
                case string:
                    myerr = myerror.New("8888", msg, t)
                case error:
                    myerr = myerror.WithCause("8888", msg, t)
                default:
                    myerr = myerror.New("8888", msg)
                }
                //      HTTP
                s.processError(myerr, w, http.StatusInternalServerError, 0)
            }
        }()

        //  
        if handlerFunc != nil {
            handlerFunc(w, r)
        }
    })
}

, EchoHandler. , HTTP Process .


func (s *Service) EchoHandler(w http.ResponseWriter, r *http.Request) {
    //    HTTP  
    _ = s.Process("POST", w, r, func(requestBuf []byte, reqID uint64) ([]byte, Header, int, error) {
        header := Header{} //  

        //            
        for key := range r.Header {
            header[key] = r.Header.Get(key)
        }
        //      ,     
        return requestBuf, header, http.StatusOK, nil
    })
}

HTTP Process. :


  • method string тАФ HTTP HTTP
  • w http.ResponseWriter, r *http.Request тАФ
  • fn func (requestBuf [] рдмрд╛рдЗрдЯ, reqID uint64) ([] рдмрд╛рдЗрдЯ, рд╣реИрдбрд░, рдЗрдВрдЯ, рдПрд░рд░) - рдЦреБрдж рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдлрдВрдХреНрд╢рди, рдпрд╣ рдПрдХ рдЗрдирдХрдорд┐рдВрдЧ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдмрдлрд░ рдФрд░ рдПрдХ рдпреВрдирд┐рдХ HTTP рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдирдВрдмрд░ (рд▓реЙрдЧрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП), рддреИрдпрд╛рд░ рдЖрдЙрдЯрдЧреЛрдЗрдВрдЧ рд░рд┐рд╕реНрдкреЙрдиреНрд╕ рдмрдлрд░ рджреЗрддрд╛ рд╣реИ , рдЖрдЙрдЯрдЧреЛрдЗрдВрдЧ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛, HTTP рд╕реНрдерд┐рддрд┐ рдФрд░ рддреНрд░реБрдЯрд┐ рдХреЗ рд╣реЗрдбрд░ред

func (s *Service) Process(method string, w http.ResponseWriter, r *http.Request, fn func(requestBuf []byte, reqID uint64) ([]byte, Header, int, error)) error {
    var myerr error

    //    HTTP 
    reqID := GetNextRequestID()

    //   HTTP 
    if s.logger != nil {
        _ = s.logger.LogHTTPInRequest(s.tx, r, reqID) //   HTTP ,   ,    
        mylog.PrintfDebugMsg("Logging HTTP in request: reqID", reqID)
    }

    //   
    mylog.PrintfDebugMsg("Check allowed HTTP method: reqID, request.Method, method", reqID, r.Method, method)
    if r.Method != method {
        myerr = myerror.New("8000", "HTTP method is not allowed: reqID, request.Method, method", reqID, r.Method, method)
        mylog.PrintfErrorInfo(myerr)
        return myerr
    }

    //       JWT ,       
    mylog.PrintfDebugMsg("Check authentication method: reqID, AuthType", reqID, s.cfg.AuthType)
    if (s.cfg.AuthType == "INTERNAL" || s.cfg.AuthType == "MSAD") && !s.cfg.UseJWT {
        mylog.PrintfDebugMsg("JWT is of. Need Authentication: reqID", reqID)

        //    HTTP Basic Authentication
        username, password, ok := r.BasicAuth()
        if !ok {
            myerr := myerror.New("8004", "Header 'Authorization' is not set")
            mylog.PrintfErrorInfo(myerr)
            return myerr
        }
        mylog.PrintfDebugMsg("Get Authorization header: username", username)

        //  
        if myerr = s.checkAuthentication(username, password); myerr != nil {
            mylog.PrintfErrorInfo(myerr)
            return myerr
        }
    }

    //   JWT -  
    if s.cfg.UseJWT {
        mylog.PrintfDebugMsg("JWT is on. Check JSON web token: reqID", reqID)

        //  token  requests cookies
        cookie, err := r.Cookie("token")
        if err != nil {
            myerr := myerror.WithCause("8005", "JWT token does not present in Cookie. You have to authorize first.", err)
            mylog.PrintfErrorInfo(myerr)
            return myerr
        }

        //  JWT  token
        if myerr = myjwt.CheckJWTFromCookie(cookie, s.cfg.JwtKey); myerr != nil {
            mylog.PrintfErrorInfo(myerr)
            return myerr
        }
    }

    //   
    mylog.PrintfDebugMsg("Reading request body: reqID", reqID)
    requestBuf, err := ioutil.ReadAll(r.Body)
    if err != nil {
        myerr = myerror.WithCause("8001", "Failed to read HTTP body: reqID", err, reqID)
        mylog.PrintfErrorInfo(myerr)
        return myerr
    }
    mylog.PrintfDebugMsg("Read request body: reqID, len(body)", reqID, len(requestBuf))

    //  
    mylog.PrintfDebugMsg("Calling external function handler: reqID, function", reqID, fn)
    responseBuf, header, status, myerr := fn(requestBuf, reqID)
    if myerr != nil {
        mylog.PrintfErrorInfo(myerr)
        return myerr
    }

    // use HSTS Strict-Transport-Security
    if s.cfg.UseHSTS {
        w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
    }

    //    
    if s.logger != nil {
        mylog.PrintfDebugMsg("Logging HTTP out response: reqID", reqID)
        _ = s.logger.LogHTTPOutResponse(s.tx, header, responseBuf, status, reqID) //   HTTP ,   ,    
    }

    //   
    mylog.PrintfDebugMsg("Set HTTP response headers: reqID", reqID)
    if header != nil {
        for key, h := range header {
            w.Header().Set(key, h)
        }
    }

    //  HTTP  
    mylog.PrintfDebugMsg("Set HTTP response status: reqID, Status", reqID, http.StatusText(status))
    w.WriteHeader(status)

    //   
    if responseBuf != nil && len(responseBuf) > 0 {
        mylog.PrintfDebugMsg("Writing HTTP response body: reqID, len(body)", reqID, len(responseBuf))
        respWrittenLen, err := w.Write(responseBuf)
        if err != nil {
            myerr = myerror.WithCause("8002", "Failed to write HTTP repsonse: reqID", err)
            mylog.PrintfErrorInfo(myerr)
            return myerr
        }
        mylog.PrintfDebugMsg("Written HTTP response: reqID, len(body)", reqID, respWrittenLen)
    }

    return nil
}

All Articles