parent
865b824c09
commit
9b751c066c
@ -1,136 +0,0 @@ |
|||||||
package middleware |
|
||||||
|
|
||||||
import ( |
|
||||||
"github.com/labstack/echo/v4" |
|
||||||
"github.com/labstack/echo/v4/middleware" |
|
||||||
"net/http" |
|
||||||
) |
|
||||||
|
|
||||||
type CORSConfig struct { |
|
||||||
// Skipper defines a function to skip middleware.
|
|
||||||
Skipper func(c echo.Context) bool |
|
||||||
|
|
||||||
// AllowOrigins determines the value of the Access-Control-Allow-Origin
|
|
||||||
// response header. This header defines a list of origins that may access the
|
|
||||||
// resource. The wildcard characters '*' and '?' are supported and are
|
|
||||||
// converted to regex fragments '.*' and '.' accordingly.
|
|
||||||
//
|
|
||||||
// Security: use extreme caution when handling the origin, and carefully
|
|
||||||
// validate any logic. Remember that attackers may register hostile domain names.
|
|
||||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
|
||||||
//
|
|
||||||
// Optional. Default value []string{"*"}.
|
|
||||||
//
|
|
||||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
|
||||||
AllowOrigins []string |
|
||||||
|
|
||||||
// AllowOriginFunc is a custom function to validate the origin. It takes the
|
|
||||||
// origin as an argument and returns true if allowed or false otherwise. If
|
|
||||||
// an error is returned, it is returned by the handler. If this option is
|
|
||||||
// set, AllowOrigins is ignored.
|
|
||||||
//
|
|
||||||
// Security: use extreme caution when handling the origin, and carefully
|
|
||||||
// validate any logic. Remember that attackers may register hostile domain names.
|
|
||||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
|
||||||
//
|
|
||||||
// Optional.
|
|
||||||
AllowOriginFunc func(origin string) (bool, error) |
|
||||||
|
|
||||||
// AllowMethods determines the value of the Access-Control-Allow-Methods
|
|
||||||
// response header. This header specified the list of methods allowed when
|
|
||||||
// accessing the resource. This is used in response to a preflight request.
|
|
||||||
//
|
|
||||||
// Optional. Default value DefaultCORSConfig.AllowMethods.
|
|
||||||
// If `allowMethods` is left empty, this middleware will fill for preflight
|
|
||||||
// request `Access-Control-Allow-Methods` header value
|
|
||||||
// from `Allow` header that echo.Router set into context.
|
|
||||||
//
|
|
||||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
|
||||||
AllowMethods []string |
|
||||||
|
|
||||||
// AllowHeaders determines the value of the Access-Control-Allow-Headers
|
|
||||||
// response header. This header is used in response to a preflight request to
|
|
||||||
// indicate which HTTP headers can be used when making the actual request.
|
|
||||||
//
|
|
||||||
// Optional. Default value []string{}.
|
|
||||||
//
|
|
||||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
|
||||||
AllowHeaders []string |
|
||||||
|
|
||||||
// AllowCredentials determines the value of the
|
|
||||||
// Access-Control-Allow-Credentials response header. This header indicates
|
|
||||||
// whether the response to the request can be exposed when the
|
|
||||||
// credentials mode (Request.credentials) is true. When used as part of a
|
|
||||||
// response to a preflight request, this indicates whether or not the actual
|
|
||||||
// request can be made using credentials. See also
|
|
||||||
// [MDN: Access-Control-Allow-Credentials].
|
|
||||||
//
|
|
||||||
// Optional. Default value false, in which case the header is not set.
|
|
||||||
//
|
|
||||||
// Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`.
|
|
||||||
// See "Exploiting CORS misconfigurations for Bitcoins and bounties",
|
|
||||||
// https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
|
||||||
//
|
|
||||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
|
||||||
AllowCredentials bool |
|
||||||
|
|
||||||
// UnsafeWildcardOriginWithAllowCredentials UNSAFE/INSECURE: allows wildcard '*' origin to be used with AllowCredentials
|
|
||||||
// flag. In that case we consider any origin allowed and send it back to the client with `Access-Control-Allow-Origin` header.
|
|
||||||
//
|
|
||||||
// This is INSECURE and potentially leads to [cross-origin](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties)
|
|
||||||
// attacks. See: https://github.com/labstack/echo/issues/2400 for discussion on the subject.
|
|
||||||
//
|
|
||||||
// Optional. Default value is false.
|
|
||||||
UnsafeWildcardOriginWithAllowCredentials bool |
|
||||||
|
|
||||||
// ExposeHeaders determines the value of Access-Control-Expose-Headers, which
|
|
||||||
// defines a list of headers that clients are allowed to access.
|
|
||||||
//
|
|
||||||
// Optional. Default value []string{}, in which case the header is not set.
|
|
||||||
//
|
|
||||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header
|
|
||||||
ExposeHeaders []string |
|
||||||
|
|
||||||
// MaxAge determines the value of the Access-Control-Max-Age response header.
|
|
||||||
// This header indicates how long (in seconds) the results of a preflight
|
|
||||||
// request can be cached.
|
|
||||||
//
|
|
||||||
// Optional. Default value 0. The header is set only if MaxAge > 0.
|
|
||||||
//
|
|
||||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
|
||||||
MaxAge int |
|
||||||
} |
|
||||||
|
|
||||||
// DefaultCORSConfig is the default CORS middleware config.
|
|
||||||
var DefaultCORSConfig = CORSConfig{ |
|
||||||
Skipper: func(c echo.Context) bool { |
|
||||||
return false |
|
||||||
}, |
|
||||||
AllowOrigins: []string{"*"}, |
|
||||||
AllowMethods: []string{ |
|
||||||
http.MethodGet, |
|
||||||
http.MethodHead, |
|
||||||
http.MethodPut, |
|
||||||
http.MethodPatch, |
|
||||||
http.MethodPost, |
|
||||||
http.MethodDelete, |
|
||||||
}, |
|
||||||
} |
|
||||||
|
|
||||||
func (c *CORSConfig) ToMiddleware() echo.MiddlewareFunc { |
|
||||||
return middleware.CORSWithConfig(middleware.CORSConfig{ |
|
||||||
Skipper: c.Skipper, |
|
||||||
AllowOrigins: c.AllowOrigins, |
|
||||||
AllowOriginFunc: c.AllowOriginFunc, |
|
||||||
AllowMethods: c.AllowMethods, |
|
||||||
AllowHeaders: c.AllowHeaders, |
|
||||||
AllowCredentials: c.AllowCredentials, |
|
||||||
UnsafeWildcardOriginWithAllowCredentials: c.UnsafeWildcardOriginWithAllowCredentials, |
|
||||||
ExposeHeaders: c.ExposeHeaders, |
|
||||||
MaxAge: c.MaxAge, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
func CORS() echo.MiddlewareFunc { |
|
||||||
return DefaultCORSConfig.ToMiddleware() |
|
||||||
} |
|
@ -1,4 +1,4 @@ |
|||||||
package middleware |
package runtime |
||||||
|
|
||||||
import ( |
import ( |
||||||
"context" |
"context" |
@ -0,0 +1,154 @@ |
|||||||
|
package rs |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"net/http" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
// ErrOK 表示没有任何错误。
|
||||||
|
// 对应 HTTP 响应状态码为 500。
|
||||||
|
ErrOK = NewError(http.StatusOK, 0, "OK") |
||||||
|
|
||||||
|
// ErrInternal 客户端请求有效,但服务器处理时发生了意外。
|
||||||
|
// 对应 HTTP 响应状态码为 500。
|
||||||
|
ErrInternal = NewError(http.StatusInternalServerError, -100, "系统内部错误") |
||||||
|
|
||||||
|
// ErrServiceUnavailable 服务器无法处理请求,一般用于网站维护状态。
|
||||||
|
// 对应 HTTP 响应状态码为 503。
|
||||||
|
ErrServiceUnavailable = NewError(http.StatusServiceUnavailable, -101, "服务不可用") |
||||||
|
|
||||||
|
// ErrUnauthorized 用户未提供身份验证凭据,或者没有通过身份验证。
|
||||||
|
// 响应的 HTTP 状态码为 401。
|
||||||
|
ErrUnauthorized = NewError(http.StatusUnauthorized, -102, "身份验证失败") |
||||||
|
|
||||||
|
// ErrForbidden 用户通过了身份验证,但是不具有访问资源所需的权限。
|
||||||
|
// 响应的 HTTP 状态码为 403。
|
||||||
|
ErrForbidden = NewError(http.StatusForbidden, -103, "不具有访问资源所需的权限") |
||||||
|
|
||||||
|
// ErrGone 所请求的资源已从这个地址转移,不再可用。
|
||||||
|
// 响应的 HTTP 状态码为 410。
|
||||||
|
ErrGone = NewError(http.StatusGone, -104, "所请求的资源不存在") |
||||||
|
|
||||||
|
// ErrUnsupportedMediaType 客户端要求的返回格式不支持。
|
||||||
|
// 比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式。
|
||||||
|
// 响应的 HTTP 状态码为 415。
|
||||||
|
ErrUnsupportedMediaType = NewError(http.StatusUnsupportedMediaType, -105, "请求的数据格式错误") |
||||||
|
|
||||||
|
// ErrUnprocessableEntity 无法处理客户端上传的附件,导致请求失败。
|
||||||
|
// 响应的 HTTP 状态码为 422。
|
||||||
|
ErrUnprocessableEntity = NewError(http.StatusUnprocessableEntity, -106, "上传了不被支持的附件") |
||||||
|
|
||||||
|
// ErrTooManyRequests 客户端的请求次数超过限额。
|
||||||
|
// 响应的 HTTP 状态码为 429。
|
||||||
|
ErrTooManyRequests = NewError(http.StatusTooManyRequests, -107, "请求次数超过限额") |
||||||
|
|
||||||
|
// ErrSeeOther 表示需要参考另一个 URL 才能完成接收的请求操作,
|
||||||
|
// 当请求方式使用 POST、PUT 和 DELETE 时,对应的 HTTP 状态码为 303,
|
||||||
|
// 其它的请求方式在大多数情况下应该使用 400 状态码。
|
||||||
|
ErrSeeOther = NewError(http.StatusSeeOther, -108, "需要更进一步才能完成操作") |
||||||
|
|
||||||
|
// ErrBadRequest 服务器不理解客户端的请求。
|
||||||
|
// 对应 HTTP 状态码为 400。
|
||||||
|
ErrBadRequest = NewError(http.StatusBadRequest, -109, "请求错误") |
||||||
|
|
||||||
|
// ErrBadParams 客户端提交的参数不符合要求
|
||||||
|
// 对应 HTTP 状态码为 400。
|
||||||
|
ErrBadParams = NewError(http.StatusBadRequest, -110, "参数错误") |
||||||
|
|
||||||
|
// ErrRecordNotFound 访问的数据不存在
|
||||||
|
// 对应 HTTP 状态码为 404。
|
||||||
|
ErrRecordNotFound = NewError(http.StatusNotFound, -111, "访问的数据不存在") |
||||||
|
) |
||||||
|
|
||||||
|
type Error struct { |
||||||
|
// 被包装的错误对象
|
||||||
|
internal error |
||||||
|
// 响应的 HTTP 状态码
|
||||||
|
status int |
||||||
|
// 错误码
|
||||||
|
code int |
||||||
|
// 错误提示消息
|
||||||
|
text string |
||||||
|
// 错误携带的响应数据
|
||||||
|
data any |
||||||
|
} |
||||||
|
|
||||||
|
func NewError(status, code int, text string) *Error { |
||||||
|
return &Error{nil, status, code, text, nil} |
||||||
|
} |
||||||
|
|
||||||
|
// Code 返回错误码
|
||||||
|
func (e *Error) Code() int { |
||||||
|
return e.code |
||||||
|
} |
||||||
|
|
||||||
|
// Text 返回错误提示
|
||||||
|
func (e *Error) Text() string { |
||||||
|
return e.text |
||||||
|
} |
||||||
|
|
||||||
|
// Data 返回携带的数据
|
||||||
|
func (e *Error) Data() any { |
||||||
|
return e.data |
||||||
|
} |
||||||
|
|
||||||
|
// Internal 返回原始错误
|
||||||
|
func (e *Error) Internal() error { |
||||||
|
return e.internal |
||||||
|
} |
||||||
|
|
||||||
|
// Unwrap 支持 errors.Unwrap() 方法
|
||||||
|
func (e *Error) Unwrap() error { |
||||||
|
return e.Internal() |
||||||
|
} |
||||||
|
|
||||||
|
// WithInternal 通过实际错误对象派生新的实例
|
||||||
|
func (e *Error) WithInternal(err error) *Error { |
||||||
|
// 由于错误比较复杂,不好做完全等于,
|
||||||
|
// 在这里就直接复制当前对象
|
||||||
|
c := *e |
||||||
|
c.internal = err |
||||||
|
return &c |
||||||
|
} |
||||||
|
|
||||||
|
// WithStatus 通过 HTTP 状态码派生新的实例
|
||||||
|
func (e *Error) WithStatus(status int) *Error { |
||||||
|
if e.status != status { |
||||||
|
c := *e |
||||||
|
c.status = status |
||||||
|
return &c |
||||||
|
} |
||||||
|
return e |
||||||
|
} |
||||||
|
|
||||||
|
// WithText 通过新的错误提示派生新的实例
|
||||||
|
func (e *Error) WithText(text string) *Error { |
||||||
|
if text != e.text { |
||||||
|
c := *e |
||||||
|
c.text = text |
||||||
|
return &c |
||||||
|
} |
||||||
|
return e |
||||||
|
} |
||||||
|
|
||||||
|
// WithData 通过携带数据派生新的实例
|
||||||
|
func (e *Error) WithData(data any) *Error { |
||||||
|
if e.data != data { |
||||||
|
c := *e |
||||||
|
c.data = data |
||||||
|
return &c |
||||||
|
} |
||||||
|
return e |
||||||
|
} |
||||||
|
|
||||||
|
// String 实现 fmt.Stringer 接口
|
||||||
|
func (e *Error) String() string { |
||||||
|
return strings.TrimSpace(fmt.Sprintf("%d %s", e.code, e.text)) |
||||||
|
} |
||||||
|
|
||||||
|
// Error 实现错误接口
|
||||||
|
func (e *Error) Error() string { |
||||||
|
return e.String() |
||||||
|
} |
Loading…
Reference in new issue