Vert.x 将 http 重定向到 https

Vert.x redirect http to https

我们用 Vert.x4 重写了我们的网络服务,我们非常满意。在将它们投入生产之前,我们希望保护它们并且我们正在尝试启用 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.it and https://www.website.it 访问(使用 letsencrypt 证书)。


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

How can I redirect http://website.it to https//website.it?

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

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

我认为您应该创建一个侦听端口 80 的 HTTP 服务器(以及您的 HTTPS 服务器),通过使用 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!

雨果

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

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

所以在我的情况下,我可以完全按照我的意愿去做,因为 http://mydomain.it is redirected to https://mydomain.it 正如预期的那样。例如,当我打电话给

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

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

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

当然如果你直接调用https版本,这个"intermediate"步骤就不会发生。


使用Vert.x

Hugo 在 中的回答给出了使用 Vertx 的有效解决方案。我有一个如下所示的主 Verticle:

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 是 "real" 网站,因为它包含我在网络服务中需要的所有逻辑(路由器、处理程序、模型...),它看起来像这样:

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 只是一个 http 服务器,永久 重定向(使用 301)到 https 版本的网络服务器。这是代码:

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。另外 this 来自 Vertx 网站的文章说这种方法是有效的:

It is common to expose HTTP servers in production through a front HTTP server / proxy like Nginx, and have it use HTTPS for incoming connections. Vert.x can also expose HTTPS by itself, so as to provide end-to-end encryption.

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


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