java.lang.Exception:主机未设置(运行 Payara micro 上的 JakartaEE 应用程序,在 nginx 后面)

java.lang.Exception: Host is not set (running a JakartaEE app on Payara micro, behind nginx)

此错误跟踪污染了我的日志,我在 SA 上找不到,否则是什么原因造成的:

[2022-01-11T04:15:00.144+0100] [] [[1;91mSEVERE[0m] [AS-WEB-CORE-00037] [[1;94mjavax.enterprise.web.core[0m] [tid: _ThreadID=27428 _ThreadName=http-thread-pool::http-listener(331)] [timeMillis: 1641870900144] [levelValue: 1000] [[
  An exception or error occurred in the container during the request processing
java.lang.Exception: Host is not set
    at org.glassfish.grizzly.http.server.util.Mapper.map(Mapper.java:865)
    at org.apache.catalina.connector.CoyoteAdapter.postParseRequest(CoyoteAdapter.java:496)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:309)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:520)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:217)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:182)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:156)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:218)
    at org.glassfish.grizzly.filterchain.ExecutorResolver.execute(ExecutorResolver.java:95)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:260)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:177)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:109)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:88)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:53)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:524)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:89)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:94)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access0(WorkerThreadIOStrategy.java:33)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:114)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:569)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:549)
    at java.base/java.lang.Thread.run(Thread.java:829)
]]

这适用于 Payara micro 5.2021.2 上带有 JSF 2.3 (Faces) 运行 的 JakartaEE 应用程序。如果这有任何相关性,以下是将流量重定向到应用程序的 nginx 配置部分:

upstream payara {
    least_conn;

    server localhost:8080 max_fails=3 fail_timeout=5s;
    server localhost:8181 max_fails=3 fail_timeout=5s;
}

    location /jsf-app-1.0-SNAPSHOT/ {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-Proto https;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_no_cache $cookie_nocache  $arg_nocache$arg_comment;
            proxy_no_cache $http_pragma     $http_authorization;
            proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
            proxy_cache_bypass $http_pragma $http_authorization;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host:$server_port;
            add_header Access-Control-Allow-Origin *;
            proxy_set_header Access-Control-Allow-Origin *;
            proxy_pass http://payara$request_uri;
    }
    
    location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto https;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        proxy_no_cache $cookie_nocache  $arg_nocache$arg_comment;
            proxy_no_cache $http_pragma     $http_authorization;
            proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
            proxy_cache_bypass $http_pragma $http_authorization;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host:$server_port;
            add_header Access-Control-Allow-Origin *;
            proxy_set_header Access-Control-Allow-Origin *;
            proxy_pass http://payara$request_uri$is_args$args;

   }

看起来 Grizzly 正试图从请求中的 Host header 获取主机名。自 HTTP 1.1 起,Host header 是必需的,但如果 Host header 设置为空名称,Grizzly 无法获取该名称并抛出异常。

Host 请求 header 由 HTTP 客户端设置。但是即使 Host header 存在但由于某种原因它的值为空也会抛出异常。

Grizzly Code: the code that throws the Exception


根据 Javadocs for Grizzly you can set the default hostname by calling the setDefaultHostName(String defaultHostName) method, but the instance of the Mapper in the HttpHanderChain instance is not exposed. The default value set in HttpHanderChain of the Mapper instance is set to "localhost".