无法从 Spring 集成出站网关调用 HTTPS 端点
Cannot call HTTPS endpoint from Spring integration outbound gateway
我有两个微服务和一个网关。一个微服务是用JHipster和spring boot(Service1)开发的,另一个有spring集成框架(IntegrationService)。现在我需要从 IntegrationService 调用 service1 API。我在两个微服务中都使用 HTTPS 进行通信。但是当调用 API 时,我得到了以下错误日志。
2021-05-05 11:05:45.503 INFO 22105 --- [ XNIO-1 task-4] c.m.a.s.IntegrationService : exception in IntegrationService org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://<server_ip>/gateway/services/service1/api/viewrecords?id=100100100100157] in the [bean 'outboundGateway'; defined in: 'class path resource [com/esi/app/service/IntegrationService.class]'; from source: 'org.springframework.core.type.classreading.SimpleMethodMetadata@3fa2213']; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://<server_ip>/gateway/services/service1/api/viewrecords": PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target, failedMessage=GenericMessage [payload={custId=100100100100157}, headers={http_requestMethod=GET, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@703c6baf, Connection=Keep-Alive, Host=<server_ip>:port, accept=/, authorization=Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImF1dGgiOiJST0xFX0FETUlOLFJPTEVfVVNFUiIsImV4cCI6MTYyMDI3ODk4NH0.-4ByR7OQY-G_dZh7XUHYOSo3FRS2Ug6JxVOkq6XOmhUV05LnQj10puEGotcJk1EUlYDvt4n2dAJFSuR3evnvHA, replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@703c6baf, http_requestUrl=http://<server_ip>:/api/getrecordsfromservice1?transactionId=1111111111&id=100100100100157, id=1eec8d00-4040-c9b2-cdb1-4f2d8743d007, Content-Length=0, http_userPrincipal=org.springframework.security.authentication.UsernamePasswordAuthenticationToken@143b9e60: Principal: org.springframework.security.core.userdetails.User@586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_ADMIN, ROLE_USER, accept-encoding=gzip, deflate, br, user-agent=PostmanRuntime/7.28.0, timestamp=1620192945487}]
我用来调用 IntegrationService 的 API 端点是,
https://<server_ip>/gateway/services/integration/api/getrecordsfromservice1?transactionId=1111111111&id=100100100100157
integration是IntegrationService在网关中注册的服务名。同样,service1 用于 Service1。
我无法理解的是:
- 如何将“http_requestUrl”更改为日志中的那个,而不是我正在访问的端点?
- 即使我在两个微服务中都使用 HTTPS,为什么会出现“SunCertPathBuilderException”?
- 要获取“主机”消息 header,是 spring 框架在配置文件 application.yml 上查找 IP 和端口,而不是检查 URL?
有人可以帮忙吗? @artem
我的入站和出站网关如下:
@ServiceActivator(inputChannel = "channelOutbound")
@Bean
public HttpRequestExecutingMessageHandler outboundGateway() {
final HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler(
viewrecordsEndpoint + "{id}");
handler.setExpectedResponseType(String.class);
handler.setHttpMethod(HttpMethod.GET);
handler.setOutputChannelName("channelOutboundResponse");
final ExpressionParser parser = new SpelExpressionParser();
final Expression exp = parser.parseExpression("payload[id]");
final Map<String, Expression> uriExp = new HashMap<>();
uriExp.put(Constants.ID, exp);
handler.setUriVariableExpressions(uriExp);
return handler;
}
@Bean
public HttpRequestHandlingMessagingGateway inboundGateway() {
final HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway();
gateway.setRequestMapping(requestMapping());
gateway.setRequestChannelName("channelInbound");
gateway.setReplyChannelName("channelInboundReply");
gateway.setErrorChannelName("channelInboundError");
return gateway;
}
private RequestMapping getGoldLoansForUcicInboundRequestMapping() {
final RequestMapping mapping = new requestMapping();
mapping.setPathPatterns("/api/getrecordsfromservice1");
mapping.setMethods(HttpMethod.GET);
return mapping;
}
Spring 集成与 HTTPS 无关。这是标准的 SSL Java 配置,必须在两侧正确提供。只是将 HTTP 架构更改为 HTTPS 是不够的。
在网上看到一些可能的解决方案:https://docs.oracle.com/cd/E19906-01/820-4916/6ngbm6hre/index.html
回复。你的 url 有问题。 API 网关可能就是这样工作的。因此,当外部请求到达其端点时,它只是剥离自己的上下文。
我有两个微服务和一个网关。一个微服务是用JHipster和spring boot(Service1)开发的,另一个有spring集成框架(IntegrationService)。现在我需要从 IntegrationService 调用 service1 API。我在两个微服务中都使用 HTTPS 进行通信。但是当调用 API 时,我得到了以下错误日志。
2021-05-05 11:05:45.503 INFO 22105 --- [ XNIO-1 task-4] c.m.a.s.IntegrationService : exception in IntegrationService org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://<server_ip>/gateway/services/service1/api/viewrecords?id=100100100100157] in the [bean 'outboundGateway'; defined in: 'class path resource [com/esi/app/service/IntegrationService.class]'; from source: 'org.springframework.core.type.classreading.SimpleMethodMetadata@3fa2213']; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://<server_ip>/gateway/services/service1/api/viewrecords": PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target, failedMessage=GenericMessage [payload={custId=100100100100157}, headers={http_requestMethod=GET, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@703c6baf, Connection=Keep-Alive, Host=<server_ip>:port, accept=/, authorization=Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImF1dGgiOiJST0xFX0FETUlOLFJPTEVfVVNFUiIsImV4cCI6MTYyMDI3ODk4NH0.-4ByR7OQY-G_dZh7XUHYOSo3FRS2Ug6JxVOkq6XOmhUV05LnQj10puEGotcJk1EUlYDvt4n2dAJFSuR3evnvHA, replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@703c6baf, http_requestUrl=http://<server_ip>:/api/getrecordsfromservice1?transactionId=1111111111&id=100100100100157, id=1eec8d00-4040-c9b2-cdb1-4f2d8743d007, Content-Length=0, http_userPrincipal=org.springframework.security.authentication.UsernamePasswordAuthenticationToken@143b9e60: Principal: org.springframework.security.core.userdetails.User@586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_ADMIN, ROLE_USER, accept-encoding=gzip, deflate, br, user-agent=PostmanRuntime/7.28.0, timestamp=1620192945487}]
我用来调用 IntegrationService 的 API 端点是,
https://<server_ip>/gateway/services/integration/api/getrecordsfromservice1?transactionId=1111111111&id=100100100100157
integration是IntegrationService在网关中注册的服务名。同样,service1 用于 Service1。
我无法理解的是:
- 如何将“http_requestUrl”更改为日志中的那个,而不是我正在访问的端点?
- 即使我在两个微服务中都使用 HTTPS,为什么会出现“SunCertPathBuilderException”?
- 要获取“主机”消息 header,是 spring 框架在配置文件 application.yml 上查找 IP 和端口,而不是检查 URL?
有人可以帮忙吗? @artem
我的入站和出站网关如下:
@ServiceActivator(inputChannel = "channelOutbound")
@Bean
public HttpRequestExecutingMessageHandler outboundGateway() {
final HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler(
viewrecordsEndpoint + "{id}");
handler.setExpectedResponseType(String.class);
handler.setHttpMethod(HttpMethod.GET);
handler.setOutputChannelName("channelOutboundResponse");
final ExpressionParser parser = new SpelExpressionParser();
final Expression exp = parser.parseExpression("payload[id]");
final Map<String, Expression> uriExp = new HashMap<>();
uriExp.put(Constants.ID, exp);
handler.setUriVariableExpressions(uriExp);
return handler;
}
@Bean
public HttpRequestHandlingMessagingGateway inboundGateway() {
final HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway();
gateway.setRequestMapping(requestMapping());
gateway.setRequestChannelName("channelInbound");
gateway.setReplyChannelName("channelInboundReply");
gateway.setErrorChannelName("channelInboundError");
return gateway;
}
private RequestMapping getGoldLoansForUcicInboundRequestMapping() {
final RequestMapping mapping = new requestMapping();
mapping.setPathPatterns("/api/getrecordsfromservice1");
mapping.setMethods(HttpMethod.GET);
return mapping;
}
Spring 集成与 HTTPS 无关。这是标准的 SSL Java 配置,必须在两侧正确提供。只是将 HTTP 架构更改为 HTTPS 是不够的。
在网上看到一些可能的解决方案:https://docs.oracle.com/cd/E19906-01/820-4916/6ngbm6hre/index.html
回复。你的 url 有问题。 API 网关可能就是这样工作的。因此,当外部请求到达其端点时,它只是剥离自己的上下文。