SiteMesh:更改响应的内容类型 [英] SiteMesh: Changing the content-type of the response
问题描述
我试图说服SiteMesh装饰器更改响应的内容类型,但没有任何乐趣.内容类型总是最终与装饰的JSP相同,而不是装饰器的类型.
I'm trying to persuade a SiteMesh decorator to change the content-type of the response, but no joy. The content-type always ends up being the same as the decorated JSP, rather than that of the decorator.
例如,假设我有一个带有标头的JSP
For example, say I have a JSP with the header
<%@ page contentType="application/xhtml+xml" %>
我还有一个SiteMesh装饰器JSP,它定义了以下内容:
I also have a SiteMesh decorator JSP which defines this:
<%@ page contentType="application/vnd.wap.xhtml+xml" %>
我想要的是修饰后的响应具有修饰符的mime类型(此处使用的实际MIME类型并不重要,这仅是为了说明问题).
What I want is for the decorated response to have the mime type of the decorator (the actual MIME type used here are not important, this is just to illustrate the problem).
对SiteMesh 2.4.1源进行的挖掘表明问题出在ContentBufferingResponse
类中,该类负责捕获目标的输出.这将覆盖setContentType()
方法,记录该值供以后使用,但它还会调用super.setContentType()
,从而有效地将目标JSP的内容类型直接传递给响应.完成此操作后,就不会有任何令人信服的说服力说服响应了.否则
A dig through the SiteMesh 2.4.1 source suggests that the problem lies with the ContentBufferingResponse
class, which is responsible for capturing the output of the target. This overrides the setContentType()
method, recording the value for later use, but it also invokes super.setContentType()
, effectively passing the content-type of the target JSP directly to the response. Once that's done, no amount of cajoling will persuade the response to do otherwise.
那么有没有解决方法?可以抑制目标JSP的内容类型,而从装饰器中获取它吗?
So is there a workaround for this? Can the content-type of the target JSP be suppressed, and taken from the decorator instead?
推荐答案
ContentBufferingResponse.setContentType
将触发对HttpServletResponseWrapper.setContentType
的调用.稍后,装饰器使用RequestDispatcher.include
包含在响应中,该装饰器无法更改状态代码或设置标头(任何进行更改的尝试都将被忽略).因此,基本上,一旦设置了内容类型,它的游戏结束了,就无法更改它.
The ContentBufferingResponse.setContentType
will trigger a call to the HttpServletResponseWrapper.setContentType
. Later, the decorator is included in the response using a RequestDispatcher.include
which cannot change the status code or set headers (any attempt to make changes is ignored). So basically, once you set the content type, its game over, you can’t change it.
据我所知,SiteMeshFilter.obtainContent
方法是实例化ContentBufferingResponse
类的唯一位置,因此SiteMeshFilter
和ContentBufferingResponse
将是寻找解决方法的地方.
From what I see, the SiteMeshFilter.obtainContent
method is the only place the ContentBufferingResponse
class is instantiated, so SiteMeshFilter
and ContentBufferingResponse
would be the places to look for workarounds.
一种可能的解决方法是在SiteMeshFilter
的子类中覆盖obtainContent
,并通过使用多态性在运行时调用正确的方法.这样做只有一个问题:obtainContent
被标记为私有,因此多态性将不起作用.要调用其他obtainContent
方法,您将不得不在过滤器中覆盖比此方法更多的内容,而且恐怕其中将包含doFilter
方法本身.
One possible workaround will be to overwrite obtainContent
in a subclass of SiteMeshFilter
and let the right method be called at runtime by use of polymorphism. There is just one problem with this: obtainContent
is marked private so polymorphism won’t work. To make a call to a different obtainContent
method you will have to overwrite a lot more than this method in the filter, and I’m afraid that will include the doFilter
method itself.
另一种解决方法是以某种方式调用setContentType
方法的另一个版本,该版本不使用修饰页面的mime类型调用super.setContentType
.但是您无法将调用更改为其他方法,因为在obtainContent
的代码中,我们使用"new"实例化了ContentBufferingResponse
实例.
Another workaround would be to somehow call another version of the setContentType
method, one that does not call super.setContentType
with the mime type of the decorated page. But you can’t change the call to another method since in obtainContent
’s code we are instantiating a ContentBufferingResponse
instance using "new".
这时,您可以在项目中创建ContentBufferingResponse
类的副本(在同一包声明下),其中setContentType
方法使用所需的mime类型而不是mime类型调用super.setContentType
从装饰页面.然后,您可以通过播放类路径并确保您的类在SiteMesh罐子中的类之前被加载,从而诱使服务器加载类而不是原始类.如果您有多个装饰器(并且我确定您有:D),那么这里的主要问题将是在不同的哑剧类型之间进行管理.
At this point you could create a copy of the ContentBufferingResponse
class in your project (under the same package declaration) one in which the setContentType
method calls super.setContentType
with the mime type you want and not the mime type from the decorated page. You can then trick the server into loading your class instead of the original, by playing with the classpath and making sure your class is loaded before the one in SiteMesh’s jar. The main problem here will be managing between different mime types if you have more than one decorator (and I’m sure you have :D).
第三个(也是丑陋的)解决方法是仅破解SiteMesh的代码并采取相应的措施(不确定是否会遇到许可证问题).
The third (also ugly) workaround will be to just hack away on SiteMesh’s code and have your way about it (not sure if you will hit issues with the license).
因此,我认为,除非您愿意采取一些丑陋的解决方法,否则一旦设置了内容类型,您将无法更改.
So, in my opinion, unless you are willing to resort to some ugly workarounds, you won’t be able to change the content type once it has been set.
这篇关于SiteMesh:更改响应的内容类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!