Java 如何在不指定servlet位置的情况下隐瞒错误代码?
在Tomcat中,我们可以在web应用程序的Java 如何在不指定servlet位置的情况下隐瞒错误代码?,java,tomcat,http-status-codes,Java,Tomcat,Http Status Codes,在Tomcat中,我们可以在web应用程序的web.xml中指定如下片段,以定义自定义错误处理程序: <error-page> <error-code>500</error-code> <location>/SomeServlet</location> </error-page> <error-page> <location>/SomeServlet</location
web.xml
中指定如下片段,以定义自定义错误处理程序:
<error-page>
<error-code>500</error-code>
<location>/SomeServlet</location>
</error-page>
<error-page>
<location>/SomeServlet</location>
</error-page>
500
/SomeServlet
还可以使用一个处理程序覆盖所有错误代码的内置页面:
<error-page>
<error-code>500</error-code>
<location>/SomeServlet</location>
</error-page>
<error-page>
<location>/SomeServlet</location>
</error-page>
/SomeServlet
正如我们所看到的,当我们这样做时,总是有一个自定义处理程序;在上面的片段中,它是/SomeServlet
但是我在想,如果我只是想对另一个现有的内置处理程序的特定错误代码撒谎,例如,撒谎说一个http404
是一个http401
,然后用http401
的内置处理程序进行响应,那该怎么办呢
我怎么能做到这一点,甚至可能做到这一点?如果不是,使用Tomcat的内置库隐瞒错误代码的最佳实践是什么?直接转发到错误页面而不是错误处理程序。也许您可以访问以下内容:
<error-code>500</error-code>
<location>/resources/errorPage404.jsp</location>
500
/参考资料/errorPage404.jsp
如果使用Spring,答案肯定就在那里,而不是Tomcat。这是一个很大的假设。我看不到Tomcat能做那样的事。然而,这并不完全是零代码
通常,处理web请求时引发的任何未经处理的异常都会导致服务器返回HTTP 500响应。但是,您自己编写的任何异常都可以使用@ResponseStatus注释进行注释(它支持HTTP规范定义的所有HTTP状态代码)。当从控制器方法抛出带注释的异常,而不是在其他地方处理时,它将自动导致使用指定的状态代码返回相应的HTTP响应
实现你自己的并使用它。通过这种方式,您可以为一个代码设置
,并在HTTP响应中为另一个代码返回响应
另一种方法是实现您自己的,但这会对性能产生重大影响
用谷歌举例说明如何实现它。这一个看起来很有趣,所以我试了一下 遗憾的是,我找不到一个好方法来实现这一点,只使用配置。但是,我确实想出了一种方法,允许您在web.xml中设置一个筛选器,并通过该筛选器的init参数“重新指定”所有HTTP状态代码 需要注意的是,使这个答案与其他答案不同的是,我确实实现了一个过滤器和一个HttpServletResponseWrapper,因为我想捕获所有角落的情况,包括响应在过滤器接收响应之前的情况。这种提交可以在不同的地方发生,例如客户端代码调用、框架等 无论如何,使用web.xml片段时,会出现如下情况:
<filter>
<filter-name>HttpStatusCodeFilter</filter-name>
<filter-class>net.stackoverflow.HttpStatusCodeConverter</filter-class>
<init-param>
<param-name>502</param-name>
<param-value>403</param-value>
</init-param>
<init-param>
<param-name>405</param-name>
<param-value>403</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HttpStatusCodeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
HttpStatusCodeFilter
net.stackoverflow.HttpStatusCodeConverter
502
403
405
403
HttpStatusCodeFilter
/*
您的Servlet过滤器(以及内部HttpServletResponseWrapper类)如下所示:
public class HttpStatusCodeConverter implements Filter {
private static final Logger logger
= Logger.getLogger(HttpStatusCodeConverter.class.getName());
private Map<Integer, Integer> errorMap;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (response instanceof HttpServletResponse) {
AntiCommitResponseWrapper hr = new AntiCommitResponseWrapper(
(HttpServletResponse) response);
//pre-filter check for error codes, if code exists, no need to continue
if (!hasFilterCode(hr)) {
//no error yet, progress through filters
try {
chain.doFilter(request, hr);
} catch (Throwable t) {
if (!hasFilterCode(hr)) {
//exception from a filter but no code was set, set it now
hr.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
}
//do post-filter check for error codes
if (hasFilterCode(hr)) {
hr.sendError(errorMap.get(hr.getStatus()));
}
hr.complete();
}
}
private boolean hasFilterCode(HttpServletResponse hr) {
return errorMap != null && errorMap.containsKey(hr.getStatus());
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) {
errorMap = new HashMap<>();
Enumeration<String> paramNames = filterConfig.getInitParameterNames();
while (paramNames.hasMoreElements()) {
String name = paramNames.nextElement();
try {
errorMap.put(Integer.valueOf(name),
Integer.valueOf(filterConfig.getInitParameter(name)));
} catch (NumberFormatException ex) {
logger.log(Level.WARNING, "Invalid HTTP status code mapping "
+ "''{0}''->''{1}''.",
new Object[]{name, filterConfig.getInitParameter(name)});
}
}
}
private class AntiCommitResponseWrapper extends HttpServletResponseWrapper {
private int status = SC_OK;
private String statusMsg;
private String redirectLocation;
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
public AntiCommitResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public int getStatus() {
return status;
}
@Override
public void setStatus(int sc) {
this.status = sc;
}
@Override
public void sendRedirect(String location) throws IOException {
this.status = SC_FOUND;
this.redirectLocation = location;
}
@Override
public void sendError(int sc) throws IOException {
this.status = sc;
}
@Override
public void sendError(int sc, String msg) throws IOException {
this.status = sc;
this.statusMsg = msg;
}
@Override
public void resetBuffer() {
buffer.reset();
}
@Override
public void reset() {
buffer.reset();
status = SC_OK;
statusMsg = null;
super.reset();
}
@Override
public void flushBuffer() throws IOException {
}
@Override
public void setBufferSize(int size) {
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener writeListener) {
try {
writeListener.onWritePossible();
} catch (IOException ex) {
}
}
@Override
public void write(int i) throws IOException {
buffer.write(i);
}
};
}
/**
* Send everything to the client.
*/
private void complete() throws IOException {
if (status != SC_OK) {
super.sendError(status, statusMsg);
} else if (status == SC_FOUND) {
super.sendRedirect(redirectLocation);
} else {
super.setStatus(status);
try (OutputStream out = super.getOutputStream()) {
out.write(buffer.toByteArray());
}
}
}
}
}
公共类HttpStatusCodeConverter实现过滤器{
专用静态最终记录器
=Logger.getLogger(HttpStatusCodeConverter.class.getName());
私人地图;
@凌驾
public void doFilter(ServletRequest请求、ServletResponse响应、,
过滤链(链条)
抛出IOException、ServletException{
if(HttpServletResponse的响应实例){
AntiCommitResponseWrapper hr=新的AntiCommitResponseWrapper(
(HttpServletResponse)响应);
//预筛选检查错误代码,如果代码存在,无需继续
如果(!hasFilterCode(hr)){
//还没有错误,正在通过筛选器进行处理
试一试{
链式过滤器(请求、人力资源);
}捕获(可丢弃的t){
如果(!hasFilterCode(hr)){
//筛选器异常,但未设置代码,请立即设置
hr.sendError(HttpServletResponse.SC\u内部\u服务器\u错误);
}
}
}
//是否执行过滤器后检查错误代码
if(hasFilterCode(hr)){
hr.sendError(errorMap.get(hr.getStatus());
}
hr.complete();
}
}
私有布尔hasFilterCode(HttpServletResponse hr){
return errorMap!=null&&errorMap.containsKey(hr.getStatus());
}
@凌驾
公共空间销毁(){
}
@凌驾
public void init(FilterConfig FilterConfig){
errorMap=新的HashMap();
枚举paramNames=filterConfig.getInitParameterNames();
while(paramNames.hasMoreElements()){
字符串名称=paramNames.nextElement();
试一试{
errorMap.put(整数.valueOf(名称),
Integer.valueOf(filterConfig.getInitParameter(name));
}捕获(NumberFormatException ex){
logger.log(Level.WARNING,“无效的HTTP状态代码映射”
+ "''{0}''->''{1}''.",
新对象[]{name,filterConfig.getInitParameter(name)});
}
}
}
私有类AntiCommitResponseWrapper扩展了HttpServletResponseWrapper{
专用int状态=SC_正常;
私有字符串statusMsg;
私有字符串重定向位置;
私有最终ByteArrayOutputStream缓冲区=新建ByteArrayOutputStream();
公共反承诺响应程序(HttpServletResponse){
超级(响应);
}
@凌驾
public int getStatus(){
返回状态;
}
@凌驾
公共状态(内部sc){
这个.status=sc;
}
@凌驾
公共void sendRedirect(字符串位置)引发IOException{
this.status=SC_FOUN