在Java Web编程中,设置 Content-Type
和 Content-Length
头部是再经常不过的操作了,但是 HttpServletResponse
提供了两个相关的方法来设置头部,一个是 void setHeader(String name, String value)
,一个是 void setContentType(String type)
或者 void setContentLength(int len)
。这两者之间有什么区别吗?之前一直分不清楚,也在代码中看到两种方式都有被人使用,甚至是两个一起写的。
我们通过阅读Tomcat相关函数的代码,来看看这两者具体有什么区别。
javax.servlet.http.HttpServletResponse#setHeader
的实现是 org.apache.catalina.connector.ResponseFacade#setHeader
,内部会调用 org.apache.catalina.connector.Response#setHeader
,源码如下:
public void setHeader(String name, String value) { if (name == null || name.length() == 0 || value == null) { return; } if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } // char cc=name.charAt(0); if (cc=='C' || cc=='c') { if (checkSpecialHeader(name, value)) return; } getCoyoteResponse().setHeader(name, value); }
在 setHeader
函数中,如果发现设置的头部已 c
或者 C
开头,会调用 checkSpecialHeader
:
// org.apache.catalina.connector.Response#checkSpecialHeader private boolean checkSpecialHeader(String name, String value) { if (name.equalsIgnoreCase("Content-Type")) { setContentType(value); return true; } return false; }
在 setHeader
函数中,为了性能,只校验第一个字母,在 checkSpecialHeader
方法中进行完整的判断,如果header的名字是不区分大小写的 Content-Type
,则调用 setContentType
函数来设置,然后直接返回。到这里我们可以知道,使用setHeader设置头部时,如果设置 Content-Type
,其实内部使用的是 setContentType
函数来实现。
那 Content-Length
呢?不着急,继续往下看。在 setHeader
函数中,如果不是 c
或者 C
开头的情况,会执行 getCoyoteResponse().setHeader(name, value)
这句话,源码如下:
// org.apache.coyote.Response#setHeader public void setHeader(String name, String value) { char cc=name.charAt(0); if( cc=='C' || cc=='c' ) { if( checkSpecialHeader(name, value) ) return; } headers.setValue(name).setString( value); }
是不是觉得眼熟,这里再一次地判断了header名称是不是以 c
或者 C
开头。但是这里的 checkSpecialHeader
实现是不一样的:
// org.apache.coyote.Response#checkSpecialHeader private boolean checkSpecialHeader( String name, String value) { // XXX Eliminate redundant fields !!! // ( both header and in special fields ) if( name.equalsIgnoreCase( "Content-Type" ) ) { setContentType( value ); return true; } if( name.equalsIgnoreCase( "Content-Length" ) ) { try { long cL=Long.parseLong( value ); setContentLength( cL ); return true; } catch( NumberFormatException ex ) { // Do nothing - the spec doesn't have any "throws" // and the user might know what he's doing return false; } } return false; }
如果header的名字是不区分大小写的 Content-Type
,则调用 setContentType
函数来设置。如果header的名字是不区分大小写的 Content-Length
,则调用 setContentLength
函数来设置。
至此我们得到了结论:通过 setHeader
来设置 Content-Type
或者 Content-Length
头部,内部是调用 setsetContentType
/ setContentLength
来实现的。所以两者功能上没有区别。但是推荐使用 setsetContentType
/ setContentLength
因为少了多余的判断,性能更高,函数名也更明义。