Apache/Tomcat 错误 - 正在传送错误的页面

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/246540/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 16:55:26  来源:igfitidea点击:

Apache/Tomcat error - wrong pages being delivered

apachetomcatajp

提问by Marcus Downing

This error has been driving me nuts. We have a server running Apache and Tomcat, serving multiple different sites. Normally the server runs fine, but sometimes an error happens where people are served the wrong page - the page that somebody elserequested!

这个错误一直让我发疯。我们有一台运行 Apache 和 Tomcat 的服务器,为多个不同的站点提供服务。通常服务器运行良好,但有时会发生错误,为人们提供错误的页面 -其他人请求的页面!

Clues:

线索:

  • The pages being delivered are those that another user requested recently, and are otherwise delivered correctly. It's been known for two simultaneous requests to be swapped. As far as I can tell, none of the pages being incorrectly delivered are older than a few minutes.
  • It only affects the files that are being served by Tomcat. Static files like images are unaffected.
  • It doesn't happen all the time. When it does happen, it happens for everybody.
  • It seems to happen at times of peak demand. However, the demand is not yet very high - it's certainly well within the bounds of what Apache can cope with.
  • Restarting Tomcat fixed it, but only for a few minutes. Restarting Apache fixed it, but only for a few minutes.
  • The server is running Apache 2 and Tomcat 6, using a Java 6 VM on Gentoo. The connection is with AJP13, and JkMountdirectives within <VirtualHost>blocks are correct.
  • There's nothing of use in any of the log files.
  • 正在传送的页面是其他用户最近请求的页面,否则会正确传送。众所周知,要交换两个同时的请求。据我所知,被错误传送的页面都不会超过几分钟。
  • 它只影响由 Tomcat 提供服务的文件。图像等静态文件不受影响。
  • 它不会一直发生。当它发生时,它会发生在每个人身上。
  • 它似乎发生在需求高峰时期。然而,需求还不是很高——它肯定在 Apache 可以应付的范围内。
  • 重新启动 Tomcat 修复了它,但只修复了几分钟。重新启动 Apache 修复了它,但只有几分钟。
  • 该服务器运行 Apache 2 和 Tomcat 6,在 Gentoo 上使用 Java 6 VM。与AJP13连接,块JkMount内指令<VirtualHost>正确。
  • 任何日志文件中都没有任何用处。


Further information:

更多信息:

Apache does not have any form of caching turned on. All the caching-related entries in httpd.conf and related imports say, for example:

Apache 没有打开任何形式的缓存。httpd.conf 和相关导入中所有与缓存相关的条目说,例如:

<IfDefine CACHE>
  LoadModule cache_module modules/mod_cache.so
</IfDefine>

While the options for Apache don't include that flag:

虽然 Apache 的选项不包括该标志:

APACHE2_OPTS="-D DEFAULT_VHOST -D INFO -D LANGUAGE -D SSL -D SSL_DEFAULT_VHOST -D PHP5 -D JK"

Tomcat likewise has no caching options switched on, that I can find.

Tomcat 同样没有打开缓存选项,我可以找到。

toolkit's suggestionwas good, but not appropriate in this case. What leads me to believe that the error can't be within my own code is that it isn't simply a few values that are being transferred - it's the entire request, including the URL, parameters, session cookies, the whole thing. People are getting pages back saying "You are logged in as John", when they clearly aren't.

toolkit 的建议很好,但在这种情况下不合适。是什么让我相信错误不能在我自己的代码中是因为它不仅仅是正在传输的几个值 - 它是整个请求,包括 URL、参数、会话 cookie 等等。人们正在返回页面说“您以约翰的身份登录”,而他们显然不是。



Update:

更新:

Based on suggestions from several people, I'm going to add the following HTTP headers to Tomcat-served pages to disable all forms of caching:

根据几个人的建议,我将向 Tomcat 服务的页面添加以下 HTTP 标头以禁用所有形式的缓存:

Cache-Control: no-store
Vary: *

Hopefully these headers will be respected not just by Apache, but also by any other caches or proxies that may be in the way. Unfortunately I have no way of deliberately reproducing this error, so I'm just going to have to wait and see if it turns up again.

希望这些标头不仅会受到 Apache 的尊重,还会受到任何其他可能妨碍的缓存或代理的尊重。不幸的是,我没有办法故意重现这个错误,所以我只能等着看它是否再次出现。

I notice that the following headers are being included - could they be related in any way?

我注意到包含以下标题 - 它们可以以任何方式相关吗?

Connection: Keep-Alive
Keep-Alive: timeout=5, max=66


Update:

更新:

Apparently this happened again while I was asleep, but has stopped happening now I'm awake to see it. Again, there's nothing useful in the logs that I can see, so I have no clues to what was actually happening or how to prevent it.

显然,这在我睡着的时候又发生了,但现在已经停止发生了,我醒了才能看到它。同样,我可以看到日志中没有任何有用的东西,所以我不知道实际发生了什么或如何防止它发生。

Is there any extra information I can put in Apache or Tomcat's logs to make this easier to diagnose?

是否有任何额外的信息可以放入 Apache 或 Tomcat 的日志中以使其更易于诊断?



Update:

更新:

Since this has happened again a couple of times, we've changed how Apache connects to Tomcat to see if it affects things. We were using mod_jkwith a directive like this:

由于这种情况再次发生了几次,我们已经更改了 Apache 连接到 Tomcat 的方式以查看它是否会影响某些事情。我们正在使用这样mod_jk的指令:

JkMount /portal ajp13

We've switched now to using mod_proxy_ajp, like so:

我们现在已经切换到 using mod_proxy_ajp,如下所示:

ProxyPass /portal ajp://localhost:8009/portal

We'll see if it makes any difference. This error was always annoyingly unpredictable, so we can never definitively say if it's worked or not.

我们会看看它是否有什么不同。这个错误总是令人讨厌地不可预测,所以我们永远无法确定它是否有效。



Update:

更新:

We just got the error briefly on a site that was left using mod_jk, while a sister site on the same server using mod_proxy_ajpdidn't show the error. This doesn't prove anything, but it does provide evidence that swithing to mod_proxy_ajpmay have helped.

我们只是在一个使用 的mod_jk站点上短暂地得到了错误,而同一台服务器上的姊妹站点 usingmod_proxy_ajp没有显示错误。这并不能证明什么,但它确实提供了证据表明切换到mod_proxy_ajp可能有所帮助。



Update:

更新:

We just got the error again last night on a site using mod_proxy_ajp, so clearly that hasn't solved it - mod_jkwasn't the source of the problem. I'm going to try the anonymous suggestion of turning off persistent connections:

昨晚我们刚刚在一个使用 的网站上再次遇到错误mod_proxy_ajp,很明显这并没有解决它 -mod_jk不是问题的根源。我将尝试关闭持久连接的匿名建议:

KeepAlive Off

If that fails as well, I'm going to be desperate enough to start investigating GlassFish.

如果这也失败了,我会非常绝望地开始研究 GlassFish。



Update:

更新:

Dammit! The problem just came back. I hadn't seen it in a while, so I was starting to think we'd finally sorted it. I hate heisenbugs.

该死!问题刚刚回来。我有一段时间没看到它了,所以我开始认为我们终于把它整理好了。我讨厌黑森虫。

采纳答案by Marcus Downing

We switched Apache from proxying with AJP to proxying with HTTP. So far it appears to have solved the issue, or at least vastly reduced it - the problem hasn't been reported in months, and the app's use has increased since then.

我们将 Apache 从使用 AJP 代理切换为使用 HTTP 代理。到目前为止,它似乎已经解决了这个问题,或者至少大大减少了它——这个问题已经几个月没有报告了,而且从那时起该应用程序的使用量有所增加。

The change is in Apache's httpd.conf. Having started with mod_jk:

更改在 Apache 的 httpd.conf 中。开始于mod_jk

JkMount /portal ajp13

We switched to mod_proxy_ajp:

我们切换到mod_proxy_ajp

ProxyPass /portal ajp://localhost:8009/portal

Then finally to straight mod_proxy:

然后终于直mod_proxy

ProxyPass /portal http://localhost:8080/portal

You'll need to make sure Tomcat is set up to serve HTTP on port 8080. And remember that if you're serving /, you need to include /on both sides of the proxy or it starts crying:

您需要确保将 Tomcat 设置为在端口 8080 上提供 HTTP 服务。请记住,如果您正在提供服务/,则需要/在代理的两端都包含,否则它会开始哭泣:

ProxyPass / http://localhost:8080/

回答by toolkit

Could it be the thread-safety of your servlets?

它可能是您的 servlet 的线程安全性吗?

Do your servlets store any information in instance members.

您的 servlet 是否在实例成员中存储任何信息。

For example, something as simple as the following may cause thread-related issues:

例如,像下面这样简单的事情可能会导致与线程相关的问题:

public class MyServlet ... {
    private String action;

    public void doGet(...) {
         action = request.getParameter("action");
         processAction(response);
    }

    public void processAction(...) {
         if (action.equals("foo")) {
             // send foo page
         } else if (action.equals("bar")) {
             // send bar page
         }
     }
}

Because the serlvet is accessed by multiple threads, there is no guarantee that the action instance member will not be clobbered by someone elses request, and end up sending the wrong page back.

因为 serlvet 是多线程访问的,所以不能保证 action 实例成员不会被别人的请求破坏,最终会发回错误的页面。

The simple solution to this issue is to use local variables insead of instance members:

这个问题的简单解决方案是在实例成员之外使用局部变量:

public class MyServlet ... {
    public void doGet(...) {
         String action = request.getParameter("action");
         processAction(action, response);
    }

    public void processAction(...) {
         if (action.equals("foo")) {
             // send foo page
         } else if (action.equals("bar")) {
             // send bar page
         }
     }
}

Note: this extends to JavaServer Pages too, if you were dispatching to them for your views?

注意:这也扩展到 JavaServer Pages,如果您为您的视图分派给它们?

回答by CesarB

Check if your headers allow caching without the correct VaryHTTP header (if you use session cookies, for instance, and allow caching, you need an entry in the VaryHTTP header for the cookie header, or a cache/proxy might serve the cached version of a page intended for one user to another user).

检查您的标头是否允许在没有正确VaryHTTP 标头的情况下进行缓存(例如,如果您使用会话 cookie 并允许缓存,则您需要在VaryHTTP 标头中为 cookie 标头提供一个条目,或者缓存/代理可能会提供缓存版本的供一个用户到另一用户的页面)。

The problem might be not with caching on your web server, but on another layer of caching (either on a reverse proxy in front of your web server, or on a proxy near the users). If the clients are behing a NAT, they might also be behind a transparent proxy (and, to make things even harder to debug, the transparent proxy might be configured to not be visible in the headers).

问题可能不在于您的 Web 服务器上的缓存,而在于另一层缓存(在您的 Web 服务器前面的反向代理上,或在用户附近的代理上)。如果客户端使用 NAT,它们也可能位于透明代理后面(并且,为了使调试更加困难,透明代理可能被配置为在标头中不可见)。

回答by Olaf Kock

8 updates of the question later one more issue to use to test/reproduce, albeit it might be difficult (or expensive) for public sites.

问题的 8 次更新之后又一个问题用于测试/重现,尽管对于公共站点来说可能很困难(或昂贵)。

You could enable https on the sites. This would at least wipe out any other proxies caches along the way. It'd be bad to see that there are some forgotten loadbalancers or company caches on the way that interfere with your traffic.

您可以在网站上启用 https。这至少会在此过程中清除任何其他代理缓存。看到有一些被遗忘的负载均衡器或公司缓存干扰您的流量会很糟糕。

For public sites this would imply trusted certificates on the keys, so some money will be involved. For testing self-signed keys might suffice. Also, check that there's no transparent proxy involved that decrypts and reencrypts the traffic. (they are easily detectable, as they can't use the same certificate/key as the original server)

对于公共站点,这意味着密钥上的可信证书,因此会涉及到一些钱。对于测试自签名密钥可能就足够了。此外,检查是否没有涉及解密和重新加密流量的透明代理。(它们很容易被检测到,因为它们不能使用与原始服务器相同的证书/密钥)

回答by William Lee

Although you did mention mod_cache was not enabled in your setup, for others who may have encountered the same issue with mod_cache enabled (even on static contents), the solution is to make sure the following directive is enabled on the Set-Cookie HTTP header:

尽管您确实提到在您的设置中未启用 mod_cache,但对于其他可能遇到启用 mod_cache 的相同问题的人(即使是在静态内容上),解决方案是确保在 Set-Cookie HTTP 标头上启用以下指令:

CacheIgnoreHeaders Set-Cookie

The reason being mod_cache will cache the Set-Cookie header that may get served to other users. This would then leak session ID from the user who last filled the cache to another.

原因是 mod_cache 将缓存可能会提供给其他用户的 Set-Cookie 标头。然后,这会将会话 ID 从上次填充缓存的用户泄漏给另一个用户。

回答by William Lee

Have a look at this site, it describes an issue with mod_jk. I came accross your posting while looking at a very similar issue. Basically the fix is to upgrade to a newer version of mod_jk. I haven't had a chance to implement the change in our server yet, but I'm going to try this tomorrow and see if it helps.

看看这个站点,它描述了一个 mod_jk 的问题。我在看一个非常相似的问题时偶然发现了你的帖子。基本上修复是升级到新版本的 mod_jk。我还没有机会在我们的服务器中实施更改,但我明天会尝试一下,看看它是否有帮助。

http://securitytracker.com/alerts/2009/Apr/1022001.html

http://securitytracker.com/alerts/2009/Apr/1022001.html

回答by user58941

I had this problem and it really drove me nuts. I dont know why, but I solved it turning off the Keep Alive on the http.conf

我遇到了这个问题,这真的让我发疯了。我不知道为什么,但我解决了它关闭 http.conf 上的 Keep Alive

from

KeepAlive On

保持活跃

to

KeepAlive Off

KeepAlive 关闭

My application doesn't use the keepalive feature, so it worked very well for me.

我的应用程序不使用 keepalive 功能,所以它对我来说效果很好。

回答by cherouvim

Try this:

尝试这个:

response.setHeader("Cache-Control", "no-cache"); //HTTP 1.1
response.setHeader("Pragma", "no-cache"); //HTTP 1.0
response.setDateHeader("Expires", 0); //prevents caching at the proxy server

回答by toolkit

I'm no expert, but could it be some weird Network Address Translationissue?

我不是专家,但这可能是一些奇怪的网络地址转换问题吗?

回答by gazum

It may be not a caching issue at all. Try to increase MaxClients parameter in apache2.conf. If it is too low (150 by default?), Apache starts to queue requests. When it decides to serve queued request via mod_proxy it pulls out a wrong page (or may be it is just stressed doing all the queuing).

这可能根本不是缓存问题。尝试增加 apache2.conf 中的 MaxClients 参数。如果它太低(默认为 150?),Apache 开始对请求进行排队。当它决定通过 mod_proxy 为排队的请求提供服务时,它会拉出一个错误的页面(或者可能只是为了完成所有排队而感到压力)。