http.go 1.5 KB

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