error_passthrough_runtime.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package service
  2. import "github.com/gin-gonic/gin"
  3. const errorPassthroughServiceContextKey = "error_passthrough_service"
  4. // BindErrorPassthroughService 将错误透传服务绑定到请求上下文,供 service 层在非 failover 场景下复用规则。
  5. func BindErrorPassthroughService(c *gin.Context, svc *ErrorPassthroughService) {
  6. if c == nil || svc == nil {
  7. return
  8. }
  9. c.Set(errorPassthroughServiceContextKey, svc)
  10. }
  11. func getBoundErrorPassthroughService(c *gin.Context) *ErrorPassthroughService {
  12. if c == nil {
  13. return nil
  14. }
  15. v, ok := c.Get(errorPassthroughServiceContextKey)
  16. if !ok {
  17. return nil
  18. }
  19. svc, ok := v.(*ErrorPassthroughService)
  20. if !ok {
  21. return nil
  22. }
  23. return svc
  24. }
  25. // applyErrorPassthroughRule 按规则改写错误响应;未命中时返回默认响应参数。
  26. func applyErrorPassthroughRule(
  27. c *gin.Context,
  28. platform string,
  29. upstreamStatus int,
  30. responseBody []byte,
  31. defaultStatus int,
  32. defaultErrType string,
  33. defaultErrMsg string,
  34. ) (status int, errType string, errMsg string, matched bool) {
  35. status = defaultStatus
  36. errType = defaultErrType
  37. errMsg = defaultErrMsg
  38. svc := getBoundErrorPassthroughService(c)
  39. if svc == nil {
  40. return status, errType, errMsg, false
  41. }
  42. rule := svc.MatchRule(platform, upstreamStatus, responseBody)
  43. if rule == nil {
  44. return status, errType, errMsg, false
  45. }
  46. status = upstreamStatus
  47. if !rule.PassthroughCode && rule.ResponseCode != nil {
  48. status = *rule.ResponseCode
  49. }
  50. errMsg = ExtractUpstreamErrorMessage(responseBody)
  51. if !rule.PassthroughBody && rule.CustomMessage != nil {
  52. errMsg = *rule.CustomMessage
  53. }
  54. // 命中 skip_monitoring 时在 context 中标记,供 ops_error_logger 跳过记录。
  55. if rule.SkipMonitoring {
  56. c.Set(OpsSkipPassthroughKey, true)
  57. }
  58. // 与现有 failover 场景保持一致:命中规则时统一返回 upstream_error。
  59. errType = "upstream_error"
  60. return status, errType, errMsg, true
  61. }