7

我们已经用 Vert.x 4 重新编写了我们的 web 服务,我们非常满意。在将它们投入生产之前,我们希望保护它们并且我们正在尝试启用 https。这是主要的垂直:

public class MainVerticle extends AbstractVerticle {

  @Override
  public void start() throws Exception {
    //Deploy the HTTP server
    vertx.deployVerticle(
      "com.albertomiola.equations.http.HttpServerVerticle",
      new DeploymentOptions().setInstances(3)
    );
  }

  // I use this only in IntelliJ Idea because when I hit "Run" the build starts
  public static void main(String[] args) {
    Launcher.executeCommand("run", MainVerticle.class.getName());
  }

}

这是 HTTP 服务器 Verticle 代码中最相关的部分:

public class HttpServerVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    var options = new HttpServerOptions();
    options.setPort(443)
           .setSSl(true)
           .setPemTrustOptions(...)
           .setPemKeyCertOptions(...);

    var server = vertx.createHttpServer(options);
    var router = Router.router(vertx);

    //Start
    server
      .requestHandler(router)
      .listen(portNumber, ar -> {
        if (ar.succeeded()) {
          startPromise.complete();
        } else {
          startPromise.fail(ar.cause());
        }
      });
  }

}

上面的代码可以正常工作,因为我的网站可以通过https://website.ithttps://www.website.it访问 (使用letsencrypt 证书)。


问题是当我尝试访问http://website.ithttp://www.website.it时它不起作用(这意味着我看不到主页,因为服务器无法访问)。

如何将http://website.it重定向到 https//website.it?

我用谷歌搜索了很多,我设法找到的是:

  • 这个vertx 示例像我一样设置 HTTPS,但它没有提到重定向
  • 这个SO question 似乎告诉我该怎么做,但我不明白该怎么做,我不确定该设置是否必须进入 HttpServerOption 对象

也许是我的 https 配置错误?我在 IntelliJ IDEA(Maven 构建)和 Vert.x 4 最新版本上使用 Java 11。谢谢

4

2 回答 2

5

我想出的最终解决方案如下所示,它们是等效的。在这两种情况下,想法都是拥有一个 http 服务器(当然是监听端口 80),它将每次调用重定向到一个 https 服务器。

所以在我的情况下,我可以做我想做的事,因为http://mydomain.it按预期重定向到https://mydomain.it 。例如,当我打电话给

http://mydomain.it/api/polynomial/laguerre

有一个活着的http服务器接收请求,但随后它立即将球扔给

https://mydomain.it/api/polynomial/laguerre

当然,如果您直接调用 https 版本,则不会发生此“中间”步骤。


使用 Vert.x

上述帖子中 Hugo 的回答给出了使用 Vertx 的有效解决方案。我有一个看起来像这样的主垂直:

public class MainVerticle extends AbstractVerticle {

  @Override
  public void start() throws Exception {

    //Deploy the HTTPS server
    vertx.deployVerticle(
      "com.albertomiola.equations.http.HttpsServerVerticle",
      new DeploymentOptions().setInstances(n)
    );

    //Deploy the HTTP server
    vertx.deployVerticle(
      "com.albertomiola.equations.http.HttpServerVerticle",
      new DeploymentOptions().setInstances(1)
    );
  }

}

第一个 verticle 是“真正的”网站,因为它包含了我在 web 服务中需要的所有逻辑(路由器、处理程序、模型......),它看起来像这样:

public class HttpsServerVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    // Setup the HTTPS
    var httpOptions = new HttpServerOptions()
      .setCompressionSupported(true)
      .setPort(443)
      .setSsl(true)
      .setPemTrustOptions(...)
      .setPemKeyCertOptions(...);

    // Start the server and the routes
    var server = vertx.createHttpServer(httpOptions);
    var router = Router.router(vertx);

    //Start
    server
      .requestHandler(router)
      .listen(ar -> {
        if (ar.succeeded()) {
          startPromise.complete();
        } else {
          startPromise.fail(ar.cause());
        }
      });
  }

}

另一个 Verticle 只是一个永久重定向(使用 301)到 https 版本的 web 服务器的 http 服务器。这是代码:

public class HttpsServerVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    var server = vertx.createHttpServer(httpOptions);
    var router = Router.router(vertx);

    //Start
    server
      .requestHandler(r -> {
          r.response()
           .setStatusCode(301)
           .putHeader("Location", r.absoluteURI().replace("http", "https"))
           .end();
      });
  }

}

通过这种方式,有 2 台服务器处于活动状态,但实际上就像只有 1 台服务器一样,因为 http 服务器(端口 80)将每次调用重定向到 https 服务器(端口 443)。


使用 Nginx

我测试过的另一种方法需要 nginx,但它与我在上面的示例中所做的事情相同。它在端口 80 上侦听 http 请求,然后将它们重定向到 https 版本。

  1. 在我的 Ubuntu 服务器上安装 Nginx(或任何你有的)
  2. 进入/etc/nginx/nginx.conf我的配置文件
  3. 添加以下代码

    http {
        server {
                listen         80;
                server_name    mydomain.it;
                return         301 https://$server_name$request_uri;
        }
    
        //other code...
    }
    
    1. 重启systemctl restart nginx

现在每个对 http 版本的调用都被重定向到 https 版本。感谢以这种方式建议我的用户injecteer 。

我使用这种方法是因为我不喜欢只为 http 版本使用单个 Verticle。Vertx网站上的这篇文章也说这种方法是有效的:

通过像 Nginx 这样的前端 HTTP 服务器/代理在生产中公开 HTTP 服务器是很常见的,并让它使用 HTTPS 进行传入连接。Vert.x 也可以自己暴露 HTTPS,从而提供端到端的加密。

所以,是的,使用 Vertx 设置 https(我建议让letsencrypt 认证),但也使用 nginx 将调用重定向到 https。


我错误地认为我可以对 Vertx 做一些特殊的事情来处理这个重定向,但这是不可能的。在这个答案中人们的建议和一些很好的谷歌搜索之后,我了解到这种方法很常见,这就是我应该做的!

于 2019-09-17T09:45:50.203 回答
1

我认为您应该创建一个监听端口 80(以及您的 HTTPS 服务器)的 HTTP 服务器,通过响应 301 HTTP 代码将所有请求重定向到其 HTTPS 等效项。

那将是这样的:

var server = vertx.createHttpServer();

server.requestHandler(req -> {
  req.response()
    .setStatusCode(301)
    .putHeader("Location", "https://" + req.host() + req.path()) // I completely made this line up and didn't test, but you have the idea
    .end();
})

希望有帮助!

雨果

ps:按照评论中的建议使用 Nginx,你会做的基本相同,但是在 Nginx 中:https ://serversforhackers.com/c/redirect-http-to-https-nginx

于 2019-09-17T09:03:50.077 回答