我用heroku创建了一个SSL端点。我有一个测试环境和一个实时环境。我有一个生成303的REST调用。由于Heroku在其路由器中处理SSL,我不知道如何检测我的SEE OTHER URL是否应创建基于HTTP或HTTPS的URI。这是一些示例代码:
@GET
@Path( "/job/{jobId}" )
public Response getCallStatus( @PathParam( "jobId" ) Long jobId, @Context UriInfo uriInfo ) throws Exception {
if ( !jobService.isDone( jobId ) )
return build( Response.ok( POLLING_FREQUENCY ) );
URI jobLocation = uriInfo.getAbsolutePathBuilder().path( "result" ).build();
return build( Response.seeOther( jobLocation ) );
}
因为我的服务器没有处理SSL(heroku是),所以REST调用的绝对路径将使用HTTP而不是HTTPS。如果我硬编码HTTPS,我将破坏我的单元测试或其他不需要HTTPS协议的环境。
有什么想法?或者我误解了heroku是如何做到这一点的?
答案 0 :(得分:0)
好的,这就是答案。 Heroku不会将请求转发为HTTPS。因此,您需要查看x-fowarded-proto标头,以确定应将303位置发送回客户端的位置。上面的代码示例将更改为:
@GET
@Path( "/job/{jobId}" )
public Response getCallStatus( @PathParam( "jobId" ) Long jobId, @Context UriInfo uriInfo, @Context HttpHeaders headers ) throws Exception {
if ( !jobService.isDone( jobId ) )
return build( Response.ok( POLLING_FREQUENCY ) );
UriBuilder builder = uriInfo.getAbsolutePathBuilder().path( "result" );
String scheme = headers.getHeaderString( "x-forwarded-proto" );
if ( scheme != null )
builder.scheme( scheme );
return build( Response.seeOther( builder.build() ) );
}
基本上就是这样。
但处理它的更好方法是不需要编码REST方法中的任何更改,就是添加一个容器请求过滤器,如下所示:
@PreMatching
public class HerokuContainerRequestFilter implements ContainerRequestFilter {
@Override
public void filter( ContainerRequestContext ctx ) throws IOException {
List<String> schemes = ctx.getHeaders().get( "x-forwarded-proto" );
if ( schemes != null && !schemes.isEmpty() ) {
String scheme = schemes.get( 0 );
UriBuilder builder = ctx.getUriInfo().getRequestUriBuilder();
ctx.setRequestUri( builder.scheme( scheme ).build() );
}
}
}
然后你只需用你的RestConfig注册这个过滤器:
public class RestApplication extends ResourceConfig {
public RestApplication() {
packages( "com.myapp.rest.service" );
// along with any other providers, etc that you register
register( HerokuContainerRequestFilter.class );
}
}
答案 1 :(得分:0)
虽然user1888440应答完全正常,但我宁愿在服务器级别配置https转发。
例如,如果你使用的是嵌入式jetty,因为你是heroku web服务器,你可以使用jetty内置的org.eclipse.jetty.server.ForwardedRequestCustomizer:
自定义代理转发请求。
此自定义程序查看标头的HTTP请求,表明它已由一个或多个代理转发。具体处理是:
- X - 转发,主机
- X - 转发,服务器
- X - 转发,对于
- X - 转发,原
如果存在这些标头,则会更新Request对象,以便代理不会被视为请求所在的连接的另一个端点
所以不要用:
启动服务器Server server = new Server(port);
您可以使用:
Server server = new Server();
HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.addCustomizer(new ForwardedRequestCustomizer());
ServerConnector serverConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
serverConnector.setPort(port);
server.addConnector(serverConnector);