proto_errors.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. package runtime
  2. import (
  3. "io"
  4. "net/http"
  5. "golang.org/x/net/context"
  6. "google.golang.org/grpc/codes"
  7. "google.golang.org/grpc/grpclog"
  8. "google.golang.org/grpc/status"
  9. )
  10. // ProtoErrorHandlerFunc handles the error as a gRPC error generated via status package and replies to the request.
  11. type ProtoErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, error)
  12. var _ ProtoErrorHandlerFunc = DefaultHTTPProtoErrorHandler
  13. // DefaultHTTPProtoErrorHandler is an implementation of HTTPError.
  14. // If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode.
  15. // If otherwise, it replies with http.StatusInternalServerError.
  16. //
  17. // The response body returned by this function is a Status message marshaled by a Marshaler.
  18. //
  19. // Do not set this function to HTTPError variable directly, use WithProtoErrorHandler option instead.
  20. func DefaultHTTPProtoErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
  21. // return Internal when Marshal failed
  22. const fallback = `{"code": 13, "message": "failed to marshal error message"}`
  23. w.Header().Del("Trailer")
  24. w.Header().Set("Content-Type", marshaler.ContentType())
  25. s, ok := status.FromError(err)
  26. if !ok {
  27. s = status.New(codes.Unknown, err.Error())
  28. }
  29. buf, merr := marshaler.Marshal(s.Proto())
  30. if merr != nil {
  31. grpclog.Printf("Failed to marshal error message %q: %v", s.Proto(), merr)
  32. w.WriteHeader(http.StatusInternalServerError)
  33. if _, err := io.WriteString(w, fallback); err != nil {
  34. grpclog.Printf("Failed to write response: %v", err)
  35. }
  36. return
  37. }
  38. md, ok := ServerMetadataFromContext(ctx)
  39. if !ok {
  40. grpclog.Printf("Failed to extract ServerMetadata from context")
  41. }
  42. handleForwardResponseServerMetadata(w, mux, md)
  43. handleForwardResponseTrailerHeader(w, md)
  44. st := HTTPStatusFromCode(s.Code())
  45. w.WriteHeader(st)
  46. if _, err := w.Write(buf); err != nil {
  47. grpclog.Printf("Failed to write response: %v", err)
  48. }
  49. handleForwardResponseTrailer(w, md)
  50. }