【问题标题】:Using nginx as a proxy to to java web servlet使用 nginx 作为代理到 java web servlet
【发布时间】:2024-04-21 20:50:01
【问题描述】:

我正在尝试使用 nginx 作为负载平衡器/代理服务器,它指向一系列 to Tomcat 服务器。这是我当前的 nginx 配置。

server {

    listen 80;
    server_name _;
    rewrite ^ https://$http_host$request_uri? permanent;
}

server {
     listen 443;

     resolver 127.0.0.11 valid=5s;

     ssl on;
     ssl_certificate /etc/nginx/certs/default.crt;        # path to your cacert.pem
     ssl_certificate_key /etc/nginx/certs/default.key;    # path to your privkey.pem
     ssl_verify_client off;
     server_name localhost;
     fastcgi_param   HTTPS               on;
     fastcgi_param   HTTP_SCHEME         https;

     charset utf-8;
     client_max_body_size 200M;

     set $app https://app:8443;
     set $auth https://auth:8443/authentication/;
     set $discovery https://discovery:8443/discovery/;

   location / {
       proxy_pass $app;
   }
   location /authentication {
       proxy_pass $auth;
   }
   location /discovery {
       proxy_pass $discovery;
       proxy_set_header Host $http_host;
       proxy_set_header X_FORWARDED_PROTO https;
   }

}

如果它有任何区别,这将被 dockerized,但是在文档工作正常时配置无法正确解决。文档和配置之间的唯一区别是“文档”通过 tomcat 提供纯 html 文件。 (tomcat7 标准 /docs/)而配置实际上是一个 java servlet(JaxRS/spring 等)。

如果我直接点击图像,它会按预期工作,而如果我尝试通过 nginx 点击同一端点,则无法解析。

我的 docker-compose 配置供参考。

version: '2'
services:
  db:
    image: db:nodata
    expose:
    - 5433
  zk:
     image: zookeeper
     ports:
     - 2181:2181
  discovery:
    image: services_discovery:latest
    env_file: docker_environment
    expose:
    - 8443
    ports:
    - 8443:8443
    links:
     - db
     - zk
  app:
    image: tomcat-jsse-ssl:7-jdk8
    volumes:
    - ./app/www/:/usr/local/tomcat7/webapps/ROOT/
    expose:
    - 8443
    ports:
    - 8444:8443
  auth:
    image: tomcat-jsse-ssl:7-jdk8
    volumes:
    - ./authentication/www/authentication/:/usr/local/tomcat7/webapps/authentication/
    expose:
    - 8443
  proxy:
    build: ./proxy/
    depends_on:
     - 'auth'
     - 'app'
     - 'discovery'
    ports:
    - 443:443
    restart: always

随着图像的运行,我可以很好地解析以下 URL。

即。两个容器都运行良好:

服务器日志:

proxy_1      | 172.20.0.1 - - [24/Apr/2017:00:04:28 +0000] "GET /discovery/ready HTTP/1.1" 404 400 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"
proxy_1      | 172.20.0.1 - - [24/Apr/2017:00:04:43 +0000] "GET /discovery/api/swagger.json HTTP/1.1" 404 400 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"
proxy_1      | 172.20.0.1 - - [24/Apr/2017:00:04:57 +0000] "GET /discovery/ready HTTP/1.1" 404 400 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"

发现Tomcat访问日志(直接访问时)

172.20.0.1 - - [23/Apr/2017:00:02:38 +0000] "GET /discovery/ready HTTP/1.1" 200 70
172.20.0.2 - - [24/Apr/2017:00:04:28 +0000] "GET /discovery/ HTTP/1.0" 404 949
172.20.0.2 - - [24/Apr/2017:00:04:43 +0000] "GET /discovery/ HTTP/1.0" 404 949
172.20.0.2 - - [24/Apr/2017:00:04:57 +0000] "GET /discovery/ HTTP/1.0" 404 949

第一个条目是当我通过https://localhost:8443/discovery/ready 直接访问服务器时,其他所有内容 是 nginx 向服务器发送请求的时候。由于某种原因,它没有正确翻译请求。

任何想法/建议将不胜感激?

注意:出于这个问题的目的,我简化了我的示例/配置,并且对“配置”的任何引用现在都是“发现”。

更新:我知道为什么它会破坏“servlet”。它实际上一直在中断。它正在剥离除基础之外的所有 URL。

例如。

https://localhost/authentication?q=dummy

变成 172.20.0.3 - - [24/Apr/2017:03:22:06 +0000] "GET /authentication/HTTP/1.0" 200 28

请注意,查询参数已被删除。

【问题讨论】:

  • 容器是否在同一个 docker 网络上?
  • 是的,同一个网络。如果我进入 nginx 容器,我会看到所有各种容器,并且可以按我所说的那样 ping 它们,只要数据是静态 html/css 似乎就可以工作。
  • 您在供应容器日志中看到错误吗?你能分辨出哪个容器产生了 404 吗?
  • 不,一切都按预期工作。如果我将 8443 上运行的端口 tomcat 暴露给我的笔记本电脑,我可以连接到 servlet,一切都按预期工作。如果我尝试通过 nginx,那就是它失败的时候。据我所知,这是 nginx 造成的问题。或者tomcat/nginx的组合。我在这里设置了一个测试用例:github.com/safaci2000/docker_loadbalancer。我正在使用相同的模式(除了不为应用程序使用 tomcat),并且对于示例来说,一切都按预期工作,但是 tomcat + servlet 会导致问题。
  • 你能从供应服务器的日志中看出,是否有请求进来吗?有可能 nginx 甚至不会尝试访问配置容器。

标签: nginx docker reverse-proxy internal-load-balancer


【解决方案1】:

nginx 文档说你有责任重建 url:

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

因此,您可以尝试使用正则表达式捕获 URI 的其余部分并将其发送到 proxy_pass 部分:

location ~* ^/discovery/(.*) {
  proxy_pass $discovery$1$is_args$args;
  .... other configs....
}

【讨论】:

  • 这对我来说太棒了!只是几个后续问题。我假设 (.*) 被映射到 $1。我从:nginx.org/en/docs/http/ngx_http_core_module.html 获得了 $vars 定义。 〜*的目的是什么
  • 啊,明白了。 ~* 将其标记为正则表达式模式。谢谢!
最近更新 更多