http.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. package common
  2. import (
  3. "bytes"
  4. "fmt"
  5. "github.com/gin-gonic/gin"
  6. "io"
  7. "net/http"
  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 src == nil || src.Body == nil {
  20. return
  21. }
  22. defer CloseResponseBodyGracefully(src)
  23. if c.Writer == nil {
  24. return
  25. }
  26. src.Body = io.NopCloser(bytes.NewBuffer(data))
  27. // We shouldn't set the header before we parse the response body, because the parse part may fail.
  28. // And then we will have to send an error response, but in this case, the header has already been set.
  29. // So the httpClient will be confused by the response.
  30. // For example, Postman will report error, and we cannot check the response at all.
  31. for k, v := range src.Header {
  32. // avoid setting Content-Length
  33. if k == "Content-Length" {
  34. continue
  35. }
  36. c.Writer.Header().Set(k, v[0])
  37. }
  38. // set Content-Length header manually
  39. c.Writer.Header().Set("Content-Length", fmt.Sprintf("%d", len(data)))
  40. c.Writer.WriteHeader(src.StatusCode)
  41. c.Writer.WriteHeaderNow()
  42. _, err := io.Copy(c.Writer, src.Body)
  43. if err != nil {
  44. LogError(c, fmt.Sprintf("failed to copy response body: %s", err.Error()))
  45. }
  46. }