httperrors.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package httperrors
  15. import (
  16. "context"
  17. "net/http"
  18. "runtime/debug"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/appctx"
  23. "yunion.io/x/pkg/util/httputils"
  24. "yunion.io/x/onecloud/pkg/i18n"
  25. )
  26. var (
  27. timeZone *time.Location
  28. )
  29. func init() {
  30. timeZone = time.Local
  31. }
  32. func GetTimeZone() *time.Location {
  33. return timeZone
  34. }
  35. func SetTimeZone(tzStr string) {
  36. if tz, _ := time.LoadLocation(tzStr); tz != nil {
  37. timeZone = tz
  38. }
  39. }
  40. func SendHTTPErrorHeader(w http.ResponseWriter, statusCode int) {
  41. w.Header().Set("Content-Type", "application/json")
  42. w.WriteHeader(statusCode)
  43. }
  44. func SetHTTPRedirectLocationHeader(w http.ResponseWriter, location string) {
  45. w.Header().Set("Location", location)
  46. }
  47. type Error struct {
  48. Code int `json:"code,omitzero"`
  49. Class string `json:"class,omitempty"`
  50. Details string `json:"details,omitempty"`
  51. }
  52. func NewErrorFromJCError(ctx context.Context, je *httputils.JSONClientError) Error {
  53. err := Error{
  54. Code: je.Code,
  55. Class: je.Class,
  56. Details: formatDetails(ctx, je.Data, je.Details),
  57. }
  58. return err
  59. }
  60. func NewErrorFromGeneralError(ctx context.Context, e error) Error {
  61. je := NewGeneralError(e)
  62. return NewErrorFromJCError(ctx, je)
  63. }
  64. func formatDetails(ctx context.Context, errData httputils.Error, msg string) string {
  65. var details string
  66. if errData.Id == "" {
  67. details = msg
  68. } else {
  69. lang := appctx.Lang(ctx)
  70. a := make([]interface{}, len(errData.Fields))
  71. for i := range errData.Fields {
  72. a[i] = errData.Fields[i]
  73. }
  74. details = i18n.P(lang, errData.Id, a...)
  75. }
  76. return details
  77. }
  78. func HTTPError(ctx context.Context, w http.ResponseWriter, msg string, statusCode int, class string, errData httputils.Error) {
  79. details := formatDetails(ctx, errData, msg)
  80. if statusCode >= 300 && statusCode <= 400 {
  81. SetHTTPRedirectLocationHeader(w, details)
  82. }
  83. // 需要在调用w.WriteHeader方法之前,设置header才能生效
  84. SendHTTPErrorHeader(w, statusCode)
  85. err := Error{
  86. Code: statusCode,
  87. Class: class,
  88. Details: details,
  89. }
  90. body := jsonutils.Marshal(err).(*jsonutils.JSONDict)
  91. body.Set("time", jsonutils.NewString(time.Now().In(timeZone).Format(time.RFC3339)))
  92. w.Write([]byte(body.String()))
  93. log.Errorf("Send error %s", details)
  94. if statusCode >= 500 {
  95. debug.PrintStack()
  96. }
  97. }
  98. func JsonClientError(ctx context.Context, w http.ResponseWriter, e *httputils.JSONClientError) {
  99. HTTPError(ctx, w, e.Details, e.Code, e.Class, e.Data)
  100. }
  101. func GeneralServerError(ctx context.Context, w http.ResponseWriter, e error) {
  102. je := NewGeneralError(e)
  103. JsonClientError(ctx, w, je)
  104. }
  105. func BadRequestError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  106. JsonClientError(ctx, w, NewBadRequestError(msg, params...))
  107. }
  108. func PaymentError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  109. JsonClientError(ctx, w, NewPaymentError(msg, params...))
  110. }
  111. func UnauthorizedError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  112. JsonClientError(ctx, w, NewUnauthorizedError(msg, params...))
  113. }
  114. func InvalidCredentialError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  115. JsonClientError(ctx, w, NewInvalidCredentialError(msg, params...))
  116. }
  117. func ForbiddenError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  118. JsonClientError(ctx, w, NewForbiddenError(msg, params...))
  119. }
  120. func NotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  121. JsonClientError(ctx, w, NewNotFoundError(msg, params...))
  122. }
  123. func NotImplementedError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  124. JsonClientError(ctx, w, NewNotImplementedError(msg, params...))
  125. }
  126. func NotAcceptableError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  127. JsonClientError(ctx, w, NewNotAcceptableError(msg, params...))
  128. }
  129. func InvalidInputError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  130. JsonClientError(ctx, w, NewInputParameterError(msg, params...))
  131. }
  132. func InputParameterError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  133. JsonClientError(ctx, w, NewInputParameterError(msg, params...))
  134. }
  135. func MissingParameterError(ctx context.Context, w http.ResponseWriter, param string) {
  136. JsonClientError(ctx, w, NewMissingParameterError(param))
  137. }
  138. func ConflictError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  139. JsonClientError(ctx, w, NewConflictError(msg, params...))
  140. }
  141. func InternalServerError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  142. JsonClientError(ctx, w, NewInternalServerError(msg, params...))
  143. }
  144. func BadGatewayError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  145. JsonClientError(ctx, w, NewBadGatewayError(msg, params...))
  146. }
  147. func TenantNotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  148. JsonClientError(ctx, w, NewTenantNotFoundError(msg, params...))
  149. }
  150. func OutOfQuotaError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  151. JsonClientError(ctx, w, NewOutOfQuotaError(msg, params...))
  152. }
  153. func NotSufficientPrivilegeError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  154. JsonClientError(ctx, w, NewNotSufficientPrivilegeError(msg, params...))
  155. }
  156. func ResourceNotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  157. JsonClientError(ctx, w, NewResourceNotFoundError(msg, params...))
  158. }
  159. func TimeoutError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  160. JsonClientError(ctx, w, NewTimeoutError(msg, params...))
  161. }
  162. func ProtectedResourceError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  163. JsonClientError(ctx, w, NewProtectedResourceError(msg, params...))
  164. }
  165. func NoProjectError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  166. JsonClientError(ctx, w, NewNoProjectError(msg, params...))
  167. }
  168. func TooManyRequestsError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
  169. JsonClientError(ctx, w, NewTooManyRequestsError(msg, params...))
  170. }