response.setHeader(Content-Type)与response.setContentType()的区别
在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
因为少了多余的判断,性能更高,函数名也更明义。