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