设置HTTP应对头
摘要:设置HTTP应对头
设置HTTP应对头
1.HTTP应对头概述
Web服务器的HTTP应对普通由以下几项造成:一个形状行,一个或多个应对头,一个空行,内容文档。设置HTTP应对头往往和设置形状行中的形状代码联合起来。例如,有好几个示意“文档地位已经扭转”的形状代码都随同着一个Location头,而401(Unauthorized)形状代码则必须随同一个WWW-Authenticate头。
但是,即使在没有设置特殊含义的形状代码时,指定应对头也是很有用的。应对头可能用来实现:设置Cookie,指定修正日期,批示阅读器依照指定的间隔刷新页面,申明文档的长度以便应用持久HTTP衔接,……等等许多其余义务。
设置应对头最常用的方法是HttpServletResponse的setHeader,该方法有两个参数,分别示意应对头的名字和值。和设置形状代码相似,设置应对头应该在发送任何文档内容之行停止。
setDateHeader方法和setIntHeadr方法专门用来设置蕴含日期和整数值的应对头,前者避免了把Java工夫转换为GMT工夫字符串的费事,后者则避免了把整数转换为字符串的费事。
HttpServletResponse还提供了许多设置常见应对头的简便方法,如下所示:
setContentType:设置Content-Type头。大少数Servlet都要用到这个方法。
setContentLength:设置Content-Length头。对于支持持久HTTP衔接的阅读器来说,这个函数是很有用的。
addCookie:设置一个Cookie(Servlet API中没有setCookie方法,由于应对往往蕴含多个Set-Cookie头)。
另外,如上节引见,sendRedirect方法设置形状代码302时也会设置Location头。
2. 常见应对头及其含义
无关HTTP头具体和残缺的阐明,请参见规范。
应对头 阐明
Allow 服务器支持哪些申请方法(如GET、POST等)。
Content-Encoding 文档的编码(Encode)方法。只要在解码之后才可能失去Content-Type头指定的内容类型。应用gzip紧缩文档可以分明地缩小HTML文档的下载工夫。Java的GZIPOutputStream可能很方便地停止gzip紧缩,但只要Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该经过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))反省阅读器能否支持gzip,为支持gzip的阅读器前往经gzip紧缩的HTML页面,为其余阅读器前往一般页面。
Content-Length 示意内容长度。只要当阅读器利用持久HTTP衔接时才需求这个数据。假设你想要应用持久衔接的劣势,可能把输出文档写入ByteArrayOutputStram,实现后查看其大小,然后把该值放入Content-Length头,最后经过byteArrayStream.writeTo(response.getOutputStream()发送内容。
Content-Type 示意前面的文档属于什么MIME类型。Servlet默以为text/plain,但通常需求显式地指定为text/html。因为常常要设置Content-Type,因此HttpServletResponse提供了一个公用的方法setContentTyep。
Date 以后的GMT工夫。你可能用setDateHeader来设置这个头以避免转换工夫格式的费事。
Expires 应该在什么时分以为文档已通过期,从而不再缓存它?
Last-Modified 文档的最后改动工夫。客户可能经过If-Modified-Since申请头提供一个日期,该申请将被视为一个条件GET,只要改动工夫迟于指定工夫的文档才会前往,否则前往一个304(Not Modified)形状。Last-Modified也可用setDateHeader方法来设置。
Location 示意客户该当到哪里去提取文档。Location通常不是间接设置的,而是经过HttpServletResponse的sendRedirect方法,该方法同时设置形状代码为302。
Refresh 示意阅读器应该在多少工夫之后刷新文档,以秒计。除了刷新以后文档之外,你还可能经过setHeader("Refresh", "5; URL=http://host/path")让阅读器读取指定的页面。
留意这种性能通常是经过设置HTML页面HEAD区的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">完成,这是由于,主动刷新或重定向对于那些不能利用CGI或Servlet的HTML编写者非常重要。然而,对于Servlet来说,间接设置Refresh头愈加方便。
留意Refresh的意义是“N秒之后刷新本页面或访问指定页面”,而不是“每隔N秒刷新本页面或访问指定页面”。因此,延续刷新要求每次都发送一个Refresh头,而发送204形状代码则可能阻止阅读器持续刷新,不管是利用Refresh头还是<META HTTP-EQUIV="Refresh" ...>。
留意Refresh头不属于HTTP 1.1正式规范的一局部,而是一个扩充,但Netscape和IE都支持它。
Server 服务器名字。Servlet普通不设置这个值,而是由Web服务器本人设置。
Set-Cookie 设置和页面关联的Cookie。Servlet不应利用response.setHeader("Set-Cookie", ...),而是应利用HttpServletResponse提供的公用方法addCookie。参见下文无关Cookie设置的探讨。
WWW-Authenticate 客户应该在Authorization头中提供什么类型的授权信息?在蕴含401(Unauthorized)形状行的应对中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。
留意Servlet普通不停止这方面的解决,而是让Web服务器的专门机制来控制受明码保护页面的访问(例如.htaccess)。
3. 实例:内容扭转时主动刷新页面
下面这个Servlet用来计算大素数。由于计算十分大的数字(例如500位)能够要花不少工夫,所以Servlet将立即前往已经找到的后果,同时在后台持续计算。后台计算利用一个优先级较低的线程以避免过多地影响Web服务器的功能。假设计算还没有实现,Servlet经过发送Refresh头批示阅读器在几秒之后持续申请新的内容。
留意,本例除了阐明HTTP应对头的用处之外,还显示了Servlet的另外两个很有价值的性能。首先,它表明Servlet可以解决多个并发的衔接,每个都有本人的线程。Servlet维护了一份已有素数计算申请的Vector表,经过查找素数个数(素数列表的长度)和数字个数(每个素数的长度)将以后申请和已有申请相婚配,把一切这些申请同步到这个列表上。第二,本例证实,在Servlet中维持申请之间的形状信息是十分容易的。维持形状信息在传统的CGI编程中是一件很费事的事件。因为维持了形状信息,阅读器可以在刷新页面时访问到正在停止的计算过程,同时也使得Servlet可以保存一个无关最近申请后果的列表,当一个新的申请指定了和最近申请相反的参数时可能立即前往后果。
PrimeNumbers.java
留意,该Servlet要用到后面给出的ServletUtilities.java。另外还要用到:PrimeList.java,用于在后台线程中创建一个素数的Vector;Primes.java,用于随机生成BigInteger类型的大数字,反省它们能否是素数。(此处略去PrimeList.java和Primes.java的代码。)
package hall;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class PrimeNumbers extends HttpServlet {
private static Vector primeListVector = new Vector();
private static int maxPrimeLists = 30;
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
int numPrimes = ServletUtilities.getIntParameter(request, "numPrimes", 50);
int numDigits = ServletUtilities.getIntParameter(request, "numDigits", 120);
PrimeList primeList = findPrimeList(primeListVector, numPrimes, numDigits);
if (primeList == null) {
primeList = new PrimeList(numPrimes, numDigits, true);
synchronized(primeListVector) {
if (primeListVector.size() >= maxPrimeLists)
primeListVector.removeElementAt(0);
primeListVector.addElement(primeList);
}
}
Vector currentPrimes = primeList.getPrimes();
int numCurrentPrimes = currentPrimes.size();
int numPrimesRemaining = (numPrimes - numCurrentPrimes);
boolean isLastResult = (numPrimesRemaining == 0);
if (!isLastResult) {
response.setHeader("Refresh", "5");
}
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Some " + numDigits + "-Digit Prime Numbers";
out.println(ServletUtilities.headWithTitle(title) +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H2 ALIGN=CENTER>" + title + "</H2>\n" +
"<H3>Primes found with " + numDigits +
" or more digits: " + numCurrentPrimes + ".</H3>");
if (isLastResult)
out.println("<B>Done searching.</B>");
else
out.println("<B>Still looking for " + numPrimesRemaining +
" more<BLINK>...</BLINK></B>");
out.println("<OL>");
for(int i=0; i<numCurrentPrimes; i++) {
out.println(" <LI>" + currentPrimes.elementAt(i));
}
out.println("</OL>");
out.println("</BODY></HTML>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
// 反省能否存在同类型申请(已经实现,或许正在计算)。
// 如存在,则前往现有后果而不是启动新的后台线程。
private PrimeList findPrimeList(Vector primeListVector,
int numPrimes,
int numDigits) {
synchronized(primeListVector) {
for(int i=0; i<primeListVector.size(); i++) {
PrimeList primes = (PrimeList)primeListVector.elementAt(i);
if ((numPrimes == primes.numPrimes()) &&
(numDigits == primes.numDigits()))
return(primes);
}
return(null);
}
}
}
PrimeNumbers.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>大素数计算</TITLE>
</HEAD>
<CENTER>
<BODY BGCOLOR="#FDF5E6">
<FORM ACTION="/servlet/hall.PrimeNumbers">
<B>要计算几个素数:</B>
<INPUT TYPE="TEXT" NAME="numPrimes" VALUE=25 SIZE=4><BR>
<B>每个素数的位数:</B>
<INPUT TYPE="TEXT" NAME="numDigits" VALUE=150 SIZE=3><BR>
<INPUT TYPE="SUBMIT" VALUE="末尾计算">
</FORM>
</CENTER>
</BODY>
</HTML>
Web服务器的HTTP应对普通由以下几项造成:一个形状行,一个或多个应对头,一个空行,内容文档。设置HTTP应对头往往和设置形状行中的形状代码联合起来。例如,有好几个示意“文档地位已经扭转”的形状代码都随同着一个Location头,而401(Unauthorized)形状代码则必须随同一个WWW-Authenticate头。
但是,即使在没有设置特殊含义的形状代码时,指定应对头也是很有用的。应对头可能用来实现:设置Cookie,指定修正日期,批示阅读器依照指定的间隔刷新页面,申明文档的长度以便应用持久HTTP衔接,……等等许多其余义务。
设置应对头最常用的方法是HttpServletResponse的setHeader,该方法有两个参数,分别示意应对头的名字和值。和设置形状代码相似,设置应对头应该在发送任何文档内容之行停止。
setDateHeader方法和setIntHeadr方法专门用来设置蕴含日期和整数值的应对头,前者避免了把Java工夫转换为GMT工夫字符串的费事,后者则避免了把整数转换为字符串的费事。
HttpServletResponse还提供了许多设置常见应对头的简便方法,如下所示:
setContentType:设置Content-Type头。大少数Servlet都要用到这个方法。
setContentLength:设置Content-Length头。对于支持持久HTTP衔接的阅读器来说,这个函数是很有用的。
addCookie:设置一个Cookie(Servlet API中没有setCookie方法,由于应对往往蕴含多个Set-Cookie头)。
另外,如上节引见,sendRedirect方法设置形状代码302时也会设置Location头。
2. 常见应对头及其含义
无关HTTP头具体和残缺的阐明,请参见规范。
应对头 阐明
Allow 服务器支持哪些申请方法(如GET、POST等)。
Content-Encoding 文档的编码(Encode)方法。只要在解码之后才可能失去Content-Type头指定的内容类型。应用gzip紧缩文档可以分明地缩小HTML文档的下载工夫。Java的GZIPOutputStream可能很方便地停止gzip紧缩,但只要Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该经过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))反省阅读器能否支持gzip,为支持gzip的阅读器前往经gzip紧缩的HTML页面,为其余阅读器前往一般页面。
Content-Length 示意内容长度。只要当阅读器利用持久HTTP衔接时才需求这个数据。假设你想要应用持久衔接的劣势,可能把输出文档写入ByteArrayOutputStram,实现后查看其大小,然后把该值放入Content-Length头,最后经过byteArrayStream.writeTo(response.getOutputStream()发送内容。
Content-Type 示意前面的文档属于什么MIME类型。Servlet默以为text/plain,但通常需求显式地指定为text/html。因为常常要设置Content-Type,因此HttpServletResponse提供了一个公用的方法setContentTyep。
Date 以后的GMT工夫。你可能用setDateHeader来设置这个头以避免转换工夫格式的费事。
Expires 应该在什么时分以为文档已通过期,从而不再缓存它?
Last-Modified 文档的最后改动工夫。客户可能经过If-Modified-Since申请头提供一个日期,该申请将被视为一个条件GET,只要改动工夫迟于指定工夫的文档才会前往,否则前往一个304(Not Modified)形状。Last-Modified也可用setDateHeader方法来设置。
Location 示意客户该当到哪里去提取文档。Location通常不是间接设置的,而是经过HttpServletResponse的sendRedirect方法,该方法同时设置形状代码为302。
Refresh 示意阅读器应该在多少工夫之后刷新文档,以秒计。除了刷新以后文档之外,你还可能经过setHeader("Refresh", "5; URL=http://host/path")让阅读器读取指定的页面。
留意这种性能通常是经过设置HTML页面HEAD区的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">完成,这是由于,主动刷新或重定向对于那些不能利用CGI或Servlet的HTML编写者非常重要。然而,对于Servlet来说,间接设置Refresh头愈加方便。
留意Refresh的意义是“N秒之后刷新本页面或访问指定页面”,而不是“每隔N秒刷新本页面或访问指定页面”。因此,延续刷新要求每次都发送一个Refresh头,而发送204形状代码则可能阻止阅读器持续刷新,不管是利用Refresh头还是<META HTTP-EQUIV="Refresh" ...>。
留意Refresh头不属于HTTP 1.1正式规范的一局部,而是一个扩充,但Netscape和IE都支持它。
Server 服务器名字。Servlet普通不设置这个值,而是由Web服务器本人设置。
Set-Cookie 设置和页面关联的Cookie。Servlet不应利用response.setHeader("Set-Cookie", ...),而是应利用HttpServletResponse提供的公用方法addCookie。参见下文无关Cookie设置的探讨。
WWW-Authenticate 客户应该在Authorization头中提供什么类型的授权信息?在蕴含401(Unauthorized)形状行的应对中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。
留意Servlet普通不停止这方面的解决,而是让Web服务器的专门机制来控制受明码保护页面的访问(例如.htaccess)。
3. 实例:内容扭转时主动刷新页面
下面这个Servlet用来计算大素数。由于计算十分大的数字(例如500位)能够要花不少工夫,所以Servlet将立即前往已经找到的后果,同时在后台持续计算。后台计算利用一个优先级较低的线程以避免过多地影响Web服务器的功能。假设计算还没有实现,Servlet经过发送Refresh头批示阅读器在几秒之后持续申请新的内容。
留意,本例除了阐明HTTP应对头的用处之外,还显示了Servlet的另外两个很有价值的性能。首先,它表明Servlet可以解决多个并发的衔接,每个都有本人的线程。Servlet维护了一份已有素数计算申请的Vector表,经过查找素数个数(素数列表的长度)和数字个数(每个素数的长度)将以后申请和已有申请相婚配,把一切这些申请同步到这个列表上。第二,本例证实,在Servlet中维持申请之间的形状信息是十分容易的。维持形状信息在传统的CGI编程中是一件很费事的事件。因为维持了形状信息,阅读器可以在刷新页面时访问到正在停止的计算过程,同时也使得Servlet可以保存一个无关最近申请后果的列表,当一个新的申请指定了和最近申请相反的参数时可能立即前往后果。
PrimeNumbers.java
留意,该Servlet要用到后面给出的ServletUtilities.java。另外还要用到:PrimeList.java,用于在后台线程中创建一个素数的Vector;Primes.java,用于随机生成BigInteger类型的大数字,反省它们能否是素数。(此处略去PrimeList.java和Primes.java的代码。)
package hall;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class PrimeNumbers extends HttpServlet {
private static Vector primeListVector = new Vector();
private static int maxPrimeLists = 30;
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
int numPrimes = ServletUtilities.getIntParameter(request, "numPrimes", 50);
int numDigits = ServletUtilities.getIntParameter(request, "numDigits", 120);
PrimeList primeList = findPrimeList(primeListVector, numPrimes, numDigits);
if (primeList == null) {
primeList = new PrimeList(numPrimes, numDigits, true);
synchronized(primeListVector) {
if (primeListVector.size() >= maxPrimeLists)
primeListVector.removeElementAt(0);
primeListVector.addElement(primeList);
}
}
Vector currentPrimes = primeList.getPrimes();
int numCurrentPrimes = currentPrimes.size();
int numPrimesRemaining = (numPrimes - numCurrentPrimes);
boolean isLastResult = (numPrimesRemaining == 0);
if (!isLastResult) {
response.setHeader("Refresh", "5");
}
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Some " + numDigits + "-Digit Prime Numbers";
out.println(ServletUtilities.headWithTitle(title) +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H2 ALIGN=CENTER>" + title + "</H2>\n" +
"<H3>Primes found with " + numDigits +
" or more digits: " + numCurrentPrimes + ".</H3>");
if (isLastResult)
out.println("<B>Done searching.</B>");
else
out.println("<B>Still looking for " + numPrimesRemaining +
" more<BLINK>...</BLINK></B>");
out.println("<OL>");
for(int i=0; i<numCurrentPrimes; i++) {
out.println(" <LI>" + currentPrimes.elementAt(i));
}
out.println("</OL>");
out.println("</BODY></HTML>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
// 反省能否存在同类型申请(已经实现,或许正在计算)。
// 如存在,则前往现有后果而不是启动新的后台线程。
private PrimeList findPrimeList(Vector primeListVector,
int numPrimes,
int numDigits) {
synchronized(primeListVector) {
for(int i=0; i<primeListVector.size(); i++) {
PrimeList primes = (PrimeList)primeListVector.elementAt(i);
if ((numPrimes == primes.numPrimes()) &&
(numDigits == primes.numDigits()))
return(primes);
}
return(null);
}
}
}
PrimeNumbers.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>大素数计算</TITLE>
</HEAD>
<CENTER>
<BODY BGCOLOR="#FDF5E6">
<FORM ACTION="/servlet/hall.PrimeNumbers">
<B>要计算几个素数:</B>
<INPUT TYPE="TEXT" NAME="numPrimes" VALUE=25 SIZE=4><BR>
<B>每个素数的位数:</B>
<INPUT TYPE="TEXT" NAME="numDigits" VALUE=150 SIZE=3><BR>
<INPUT TYPE="SUBMIT" VALUE="末尾计算">
</FORM>
</CENTER>
</BODY>
</HTML>