赞
踩
proto生成后的java类就不贴了,太多,用插件自动生成就行
syntax = "proto3"; option java_multiple_files = false; option java_outer_classname = "JwtProto"; service AuthService { // 一元rpc rpc validToken(JwtRequest) returns (R){} } message JwtRequest { string token = 1; bool valid_data = 2; string func_id = 3; } message R { int32 code = 1; } // 自定义异常信息 message ErrorInfo { int32 code = 1; string msg = 2; }
import lombok.extern.slf4j.Slf4j; import net.devh.boot.grpc.server.service.GrpcService; @Slf4j @GrpcService public class AuthService extends AuthServiceGrpc.AuthServiceImplBase { @Override public void validToken(JwtProto.JwtRequest req, StreamObserver<JwtProto.R> respObserver) { String token = req.getToken(); String funcId = req.getFuncId(); log.info("validToken,[funcId:{}],[token:{}]", funcId, token); // 假设这里需要抛出业务异常 if (xxx) { throw new BusinessException(ResultEnum.ERR_SYSTEM_GRPC); } JwtProto.R r = JwtProto.R.newBuilder().setCode(ResultEnum.SUCCESS.getCode()).build(); respObserver.onNext(r); respObserver.onCompleted(); } }
BusinessException:自定义业务异常
ResultEnum:全局业务返回枚举定义,与功能无关
@Getter @AllArgsConstructor public enum ResultEnum { SUCCESS(0, ""), /** * 系统级错误(0-50] */ ERR(1, "系统错误"), ERR_SYSTEM_GRPC(2, "gRPC异常"), ; private final Integer code; private final String msg; public static ResultEnum of(Integer value) { if (value != null) { for (ResultEnum e : ResultEnum.values()) { if (e.getCode().equals(value)) { return e; } } } return null; } }
import com.google.protobuf.Any; import com.google.rpc.Code; import com.google.rpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.protobuf.StatusProto; import net.devh.boot.grpc.server.advice.GrpcAdvice; import net.devh.boot.grpc.server.advice.GrpcExceptionHandler; @GrpcAdvice public class GlobalGrpcExceptionHandler { @GrpcExceptionHandler(BusinessException.class) public StatusRuntimeException businessExceptionHandle(BusinessException e) { JwtProto.ErrorInfo errorInfo = JwtProto.ErrorInfo.newBuilder().setCode(e.getCode()).setMsg(e.getMsg()).build(); var status = Status.newBuilder() .setCode(Code.UNKNOWN.getNumber()) .setMessage(e.getMsg()) .addDetails(Any.pack(errorInfo)) .build(); return StatusProto.toStatusRuntimeException(status); } }
在全局异常处理的地方封装自定义的ErrorInfo对象,然后提供给客户端
@Slf4j @Component public class JwtUtils { @GrpcClient("auth") private AuthServiceGrpc.AuthServiceStub authStub; private static AuthServiceGrpc.AuthServiceStub authStaticStub; @PostConstruct public void init() { authStaticStub = authStub; } public static void validateToken() { // 简化传参 authStaticStub.validToken(JwtProto.JwtRequest.newBuilder().setToken("xxx123").build()); } }
import com.google.protobuf.InvalidProtocolBufferException; import com.google.rpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.protobuf.StatusProto; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Optional; @Slf4j @ControllerAdvice public class GlobalException { @ResponseBody @ExceptionHandler(StatusRuntimeException.class) public R<?> statusRuntimeException(StatusRuntimeException grpcException) { log.error("gRPCException, {}", grpcException.getMessage(), grpcException); Status status = StatusProto.fromThrowable(grpcException); if (status != null) { Optional<JwtProto.ErrorInfo> first = status.getDetailsList().stream().filter(d -> d.is(JwtProto.ErrorInfo.class)).map(d -> { try { return d.unpack(JwtProto.ErrorInfo.class); } catch (InvalidProtocolBufferException ex) { throw new RuntimeException(ex); } }).findFirst(); if (first.isPresent()) { JwtProto.ErrorInfo error = first.get(); return R.fail(ResultEnum.of(error.getCode()), error.getMsg()); } } return R.fail(ResultEnum.ERR_SYSTEM_GRPC); } }
client的全局异常主要是对响应给用户的处理
@GrpcAdvice
和 @GrpcExceptionHandler
BlockingStub
几乎没区别),本文主要是处理同步中的异常。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。