使用Heroku和303的SSL端点

时间:2014-02-04 16:42:07

标签: rest ssl heroku

我用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是如何做到这一点的?

2 个答案:

答案 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);