http.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. package common
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "github.com/gin-gonic/gin"
  8. )
  9. func CloseResponseBodyGracefully(httpResponse *http.Response) {
  10. if httpResponse == nil || httpResponse.Body == nil {
  11. return
  12. }
  13. err := httpResponse.Body.Close()
  14. if err != nil {
  15. SysError("failed to close response body: " + err.Error())
  16. }
  17. }
  18. func IOCopyBytesGracefully(c *gin.Context, src *http.Response, data []byte) {
  19. if c.Writer == nil {
  20. return
  21. }
  22. body := io.NopCloser(bytes.NewBuffer(data))
  23. // We shouldn't set the header before we parse the response body, because the parse part may fail.
  24. // And then we will have to send an error response, but in this case, the header has already been set.
  25. // So the httpClient will be confused by the response.
  26. // For example, Postman will report error, and we cannot check the response at all.
  27. if src != nil {
  28. for k, v := range src.Header {
  29. // avoid setting Content-Length
  30. if k == "Content-Length" {
  31. continue
  32. }
  33. c.Writer.Header().Set(k, v[0])
  34. }
  35. }
  36. // set Content-Length header manually BEFORE calling WriteHeader
  37. c.Writer.Header().Set("Content-Length", fmt.Sprintf("%d", len(data)))
  38. // Write header with status code (this sends the headers)
  39. if src != nil {
  40. c.Writer.WriteHeader(src.StatusCode)
  41. } else {
  42. c.Writer.WriteHeader(http.StatusOK)
  43. }
  44. _, err := io.Copy(c.Writer, body)
  45. if err != nil {
  46. LogError(c, fmt.Sprintf("failed to copy response body: %s", err.Error()))
  47. }
  48. }