proxy.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package middleware
  2. import (
  3. "context"
  4. "net/http"
  5. "net/http/httputil"
  6. "net/url"
  7. "github.com/0xJacky/Nginx-UI/internal/transport"
  8. "github.com/0xJacky/Nginx-UI/query"
  9. "github.com/gin-gonic/gin"
  10. "github.com/spf13/cast"
  11. "github.com/uozi-tech/cosy/logger"
  12. )
  13. func Proxy() gin.HandlerFunc {
  14. return func(c *gin.Context) {
  15. nodeID, ok := c.Get("ProxyNodeID")
  16. if !ok {
  17. c.Next()
  18. return
  19. }
  20. id := cast.ToUint64(nodeID)
  21. if id == 0 {
  22. c.Next()
  23. return
  24. }
  25. defer c.Abort()
  26. env := query.Environment
  27. environment, err := env.Where(env.ID.Eq(id)).First()
  28. if err != nil {
  29. logger.Error(err)
  30. c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{
  31. "message": err.Error(),
  32. })
  33. return
  34. }
  35. baseUrl, err := url.Parse(environment.URL)
  36. if err != nil {
  37. logger.Error(err)
  38. c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
  39. "message": err.Error(),
  40. })
  41. return
  42. }
  43. proxy := httputil.NewSingleHostReverseProxy(baseUrl)
  44. customTransport, err := transport.NewTransport()
  45. if err != nil {
  46. logger.Error(err)
  47. c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
  48. "message": err.Error(),
  49. })
  50. return
  51. }
  52. proxy.Transport = customTransport
  53. defaultDirector := proxy.Director
  54. proxy.Director = func(req *http.Request) {
  55. defaultDirector(req)
  56. req.Header.Del("X-Node-ID")
  57. req.Header.Set("X-Node-Secret", environment.Token)
  58. }
  59. // fix https://github.com/0xJacky/nginx-ui/issues/342
  60. proxy.ModifyResponse = func(resp *http.Response) error {
  61. if resp.StatusCode == http.StatusForbidden {
  62. resp.StatusCode = http.StatusServiceUnavailable
  63. }
  64. return nil
  65. }
  66. proxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, err error) {
  67. logger.Error(err)
  68. c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
  69. "message": err.Error(),
  70. })
  71. }
  72. logger.Debug("Proxy request", baseUrl.String()+c.Request.RequestURI)
  73. // fix proxy panic when client disconnect
  74. ctx := context.WithValue(
  75. c.Request.Context(),
  76. http.ServerContextKey,
  77. nil,
  78. )
  79. req := c.Request.Clone(ctx)
  80. proxy.ServeHTTP(c.Writer, req)
  81. return
  82. }
  83. }