深入Jetty源码之Servlet框架及实现(ServletRequest、ServletResponse)

简介:

概述

Servlet是Server Applet的缩写,即在服务器端运行的小程序,而Servlet框架则是对HTTP服务器(Servlet Container)和用户小程序中间层的标准化和抽象。这一层抽象隔离了HTTP服务器的实现细节,而Servlet规范定义了各个类的行为,从而保证了这些“服务器端运行的小程序”对服务器实现的无关性(即提升了其可移植性)。
在Servlet规范有以下几个核心类(接口):
ServletContext :定义了一些可以和Servlet Container交互的方法。
Registration :实现Filter和Servlet的动态注册。
ServletRequest(HttpServletRequest) :对HTTP请求消息的封装。
ServletResponse(HttpServletResponse) :对HTTP响应消息的封装。
RequestDispatcher :将当前请求分发给另一个URL,甚至ServletContext以实现进一步的处理。
Servlet(HttpServlet) :所有“服务器小程序”要实现了接口,这些“服务器小程序”重写doGet、doPost、doPut、doHead、doDelete、doOption、doTrace等方法(HttpServlet)以实现响应请求的相关逻辑。
Filter(FilterChain) :在进入Servlet前以及出Servlet以后添加一些用户自定义的逻辑,以实现一些横切面相关的功能,如用户验证、日志打印等功能。
AsyncContext :实现异步请求处理。

ServletRequest

ServletRequest是对Servlet请求消息的封装,其子接口HttpServletRequest则是对HTTP请求消息的封装,在Servlet框架中默认实现了ServletRequestWrapper和HttpServletRequestWrapper以便利用户对请求的Wrap。

在Jetty中,使用Request类实现HttpServletRequest接口,Request包含了HttpConnection引用,因为HttpConnection包含了HttpParser解析HTTP请求后的所有信息,如请求行、请求头以及请求内容。其中ServletRequest接口定义与实现如下:
public  interface ServletRequest {
     / / Request级别的Attribute操作,它属于Request的私有数据,因而Request使用Attributes私有字段实现。然而Jetty添加了一些自定义的Attribute:
    // 在getAttribute时,org.eclipse.jetty.io.EndPoint.maxIdleTime用于获取EndPoint中MaxIdleTime属性,org.eclipse.jetty.continuation用于获取Continuation实例(如果该属性没被占用)
     // 在setAttribute时,org.eclipse.jetty.server.Request.queryEncoding属性同时用于设置Request的QueryEncoding属性;
    // org.eclipse.jetty.server.sendContent同时用于直接向客户端发送Object指定的相应内容,该值必须是HttpContent、Resource、Buffer、InputStream类型;
     // org.eclipse.jetty.server.ResponseBuffer同时用于设置对客户端相应的ByteBuffer数据;org.eclipse.jetty.io.EndPoint.maxIdleTime同时用于设置EndPoint中的MaxIdleTime属性。
     // 如果注册了ServletRequestAttributeListener,则相应的attributeAdded、attributeReplaced、attributeRemoved方法会被调用。
     public Object getAttribute(String name);
     public Enumeration<String> getAttributeNames();
     public  void setAttribute(String name, Object o);
     public  void removeAttribute(String name);

     / / CharacterEncoding属性,用于指定读取请求内容时使用的编码方式,如果设置的编码方式不支持,抛出UnsupportedEncodingException。CharacterEncoding的设置必须在读取Parameter或getReader方法的调用之前,不然该方法不会有效果。该属性默认为null,此时Jetty默认使用UTF-8编码Parameter,使用ISO-8859-1编码方式创建Reader实例。
     public String getCharacterEncoding();
     public  void setCharacterEncoding(String env)  throws UnsupportedEncodingException;

     // 请求内容的长度,以字节为单位,-1表示长度未知。该值从HttpConnection的RequestFields字段中获取,该字段在HttpParser解析HTTP请求消息时填充。
     public  int getContentLength();
    
     / / 返回请求内容的MIME type,即在请求头中设置的ContentType头,该值同样从HttpConnection的RequestFields字段中获取,该字段在HttpParser解析HTTP请求消息时填充。
     public String getContentType();
    
     // 使用ServletInputStream包装请求内容的读取,该方法和getReader方法,只能使用一种方式来读取请求内容,否则抛出IllegalStateException。
    // ServletInputStream继承自InputStream,它只是实现了一个readLine函数。在该方法实现中返回HttpConnection的getInputStream,在该方法返回前,如果当前请求有Expect: 100-continue头,则先向客户端发送100 Continue相应,然后返回HttpInput实例,它继承自ServletInputStream,从HttpParser中读取数据。

     public ServletInputStream getInputStream()  throws IOException; 
     
     / / 请求参数相关的操作,请求参数可以在URL使用?paramName=paramValue&...的方式指定,也可是使用POST/PUT方法在请求消息体中指定(ContentType: application/x-www-form-urlencoded),或同时存在。URL的parameter信息读取使用queryEncoding字段指定的编码方式(默认编码为UTF-8),请求消息体中信息读取使用characterEncoding字段指定的编码方式(默认编码为ISO-8859-1)。在读取请求消息体中的parameter数据时,可以使用ContextHandler中的MaxFormContentSize属性或Server中的org.eclipse.jetty.server.Request.maxFormContentSize的Attribute配置最大支持的parameter数据大小,如果ContentLength超过该值,则抛出IllegalStateException。
     / / 相同的paramName可以多次出现,因而一个paramName可能对应多个值,此时使用getParameterValues()方法获取所有的值。
    // 如果使用POST指定请求参数,使用getInputStream或getReader读取数据会对parameter的读取有影响。

     public String getParameter(String name);
     public Enumeration<String> getParameterNames();
     public String[] getParameterValues(String name);
     public Map<String, String[]> getParameterMap();
    
     // 返回当前请求使用的协议以及其版本号,如HTTP/1.1,对HTTP请求,它在解析请求行时设置。
     public String getProtocol();
    
     / / 返回请求的Schema,默认为http,在SSL相关的Connector的customize方法中会被设置为https。
     public String getScheme();
    
     // 返回当前请求发送的服务器名称,如果请求URI中包含Host Name信息,则ServerName使用该信息;否则使用Host头(值为host:port)中的Server Name信息;
    // 如果不存在Host头,尝试使用EndPont中的LocalHost(LocalAddr,如果_dns值设置为false,即Connector的ResolveNames属性为false,其默认值为false);
    // 否则使用当前Server的LocalHost的Address:InetAddress.getLocalHost().getHostAddress();
    // 对代理服务器,如果Jetty在Connector中开启了forwarded检查,如果Connector中设置了_hostHeader值,则使用强制设置Host头为该值,清除已有的ServerName和Port,并重新计算;
    // 否则如果存在X-Forwarded-Host头,强制设置Host头为该头值的最左边的值,即第一个代理服务器的主机名,清除已有的ServerName和Port,并重新计算;
    // 如果存在X-Forwarded-Server头,则强制设置Request的ServerName值为该头值的最左边的值,即第一个代理服务器的主机名。
    // 如果存在X-Forwarded-For头,则更新Request的RemoteAddr和RemoteHost值,即最原始客户端的地址和主机名。
    // 如果存在X-Forwarded-Proto头,则更新Request的Schema为该头值的最左边的值。(这是原始请求的Schema还是神马呢?)
    // 具体参考:
http://benni82.iteye.com/blog/849139
     public String getServerName();

     // ServerPort有一下查找路径:请求URI中的Port;Host头中值的Port;EndPoint的LocalPort;如果都没有找到,则对HTTPS默认值为443,对HTTP默认值为80
     public  int getServerPort();
    
     // 将ServletInputStream包裹成BufferedReader类型,使用CharacterEncoding编码方式,如果没有设置该编码,默认使用ISO-8559-1,因而CharacterEncoding的设置必须在该方法调用之前。
     public BufferedReader getReader()  throws IOException;
    
     // 返回客户端的IP地址,如果开启了forwarded检查,则该值会被更新为原始的客户端请求IP,即使该请求穿越了好几个代理服务器。
     public String getRemoteAddr();

     // 如果Connector设置了ResolveNames属性为true,即Request中_dns字段为true,则返回客户端主机名,否则返回客户端主机IP;如果开启了forwarded检查,则该值被更新为最原始的客户端的主机名或IP,即使该请求穿越了好几个代理服务器。
     public String getRemoteHost();

     // 返回Accept-Language请求头中的指定的Locale值,支持多个值,以",", " ", "\t"等字符分隔,每个值都可以是如下格式:language-<country>;q<value>或language-<country>; q=<value>的格式,在选择一个Locale时使用qValue最大的那个。如果没有设置,默认使用当前服务器的Locale值。
     public Locale getLocale();

     // 返回Accept-Language头中指定的所有Locale枚举值,以qValue的值降序排列,如果没有指定该头,使用服务器默认的Locale值。
     public Enumeration<Locale> getLocales();

     / / 检查当前请求是否在安全传输通道,如https。
     public  boolean isSecure();
    
     // 返回一个RequestDispatcher,内部使用ServletContext获取RequestDispatcher实例,根据传入的path计算uriInContext值:如果它以"/"开头,uriInContext的值即为该值,
    // 如果它不以"/"开头,即表示它是相对与当前请求的path,则uriInContext的值为相对于当前Request URI,如pathInfo为/foo/goo,path为poo,则uriInContext为:<servletPath>/foo/poo
    public RequestDispatcher getRequestDispatcher(String path);
    
     // 返回客户端的端口,调用EndPoint的getRemotePort方法。
     public  int getRemotePort();

     // 返回当前服务器的主机名,如果Connector的ResolveNames为true,否则为当前服务器的IP地址。
     public String getLocalName();

     // 返回当前服务器的IP地址,调用EndPoint的getLocalAddr方法。
     public String getLocalAddr();

     // 返回当前服务器的端口号,即当前连接使用的端口号,不是服务器本身监听的端口号。
     public  int getLocalPort();

     // 返回当前Request正在执行所在ServletContext。
     public ServletContext getServletContext();

     // 启动当前请求的异步模式,该方法调用后,即可以推出当前请求的处理方法,在退出之前需要将返回的AsyncContext放到一个等待Queue或类似的数据结构中,从而在之后的处理中还能得到这个
    // AsyncContext实例进一步处理这个Request,AsyncContext包含了对当前Request和Response实例的引用,一般唤起这个异步的请求,使用AsyncContext的dispatch方法,
    // 从而保证在下一次的处理过程中依然存在Filter链通道。这个方法和带ServletRequest、ServletResponse参数的方法区别在于:
    // 如果Servlet A对应为/url/A,在Servlet A中调用request.getRequestDispatcher("/url/B"),此时在Servlet B中,如果调用request.startAsync().dispatch(),此时会dispatch到/url/A,
    // 但是如果在Servlet B中调用request.startAsync(request, response).dispatch(),此时会dispatch到/url/B中。
    // 另外该方法会在调用之前注册的AsyncListener的onStartAsync()方法之后,清除这些已注册的AsyncListener。在onStartAsync方法中可以将自己重新注册到AsyncContext中,只是这个设计好奇怪。。。

     public AsyncContext startAsync()  throws IllegalStateException;
     public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
             throws IllegalStateException;

     // 查看是否当前request异步模式已经启动,即已经调用startAsync方法,但是还没有调用AsyncContext中的dispatch或onComplete方法。
     public  boolean isAsyncStarted();

     // 查看当前Request是否支持异步模式,默认为true,如果Filter或Servlet不支持异步模式,这在调用对应的doFilter、service之前会把该值设置为false。
     public  boolean isAsyncSupported();

     // 获取最近一次调用startAsync方法时创建的AsyncContext实例,如果当前request没有异步模式还没有启动,则抛出IllegalStateException。
     public AsyncContext getAsyncContext();

     // 获取当前请求的Dispatcher类型。Dispatcher Type是Container用于选区对应的Filter链。请求最初为Dispatcher.REQUEST;如果调用RequestDispatcher.forward()方法,
    // 则变为DispatcherType.FORWARD;如果调用RequestDispatcher.include()方法,则变为DispatcherType.INCLUDE;如果调用AsyncContext.dispatch()方法,则变为
    // DispatcherType.ASYNC;最后如果请求被dispatch到error page中,则为DispatcherType.ERROR。
     // DispatcherType在HttpConnection中的handleRequest方法中,在调用server.handle()/server.handleAsync()方法之前,设置为REQUEST、ASYNC,根据当前Request的AsyncContext是否处于初始化状态,如果是,则为REQUEST,否则为ASYNC状态,其他值则在Dispatcher中forward或include方法中设置。
     public DispatcherType getDispatcherType();
}
HttpServletRequest接口定义如下:
public  interface HttpServletRequest  extends ServletRequest {
     / / Servlet的四种验证方式(他们在web.xml文件中的long-config/auth-method中定义):
    // BASIC使用Authentication头传输认证信息,该信息以Base64的编码方式编码,当需要用户验证时会弹出登陆窗口。
    // FORM使用表单的方式认证,用户名和密码在j_username和j_password字段中,登陆URL为/j_security_check,第一次使用表单方式明文传输,之后将认证信息存放在Session中,在Session实效之前可以不用在手动登陆。
    // DIGEST也时使用Authentication头传输认证信息,但是它使用加密算法将密码加密。
    // CLIENT_CERT则使用客户端证书的方式传输认证信息。
    // 更详细的内容参考:
http://docs.oracle.com/cd/E19798-01/821-1841/bncas/index.html  
     public  static  final String BASIC_AUTH = "BASIC";
     public  static  final String FORM_AUTH = "FORM";
     public  static  final String CLIENT_CERT_AUTH = "CLIENT_CERT";
     public  static  final String DIGEST_AUTH = "DIGEST";

     // 返回当前请求的认证方法,可以是BASIC、FORM、CLIENT_CERT、DIGEST。如果没有定义对应Servlet的认证配置,则返回null。在Jetty实现中,在ServletHandler根据配置信息以及认证的结果设置请求的Authentication实例,如果Authentication实例是Authentication.Deffered实例,则先验证,并设置验证后的Authentication实例,如果Authentication实例是Authentication.User实例,则设置返回其AuthMethod属性,否则返回null。
     public String getAuthType();

     // 返回当前请求包含的Cookie数组,从请求的Cookie头中获取,如果没有Cookie信息,则返回null。在Jetty实现中,使用CookieCutter类解析Cookie头。
    // Cookie值的格式为:<name>=value; [$path=..; $domain=...; $port=...; $version=..]; <name>=<value>.....
    // 在Servlet中,Cookie类包含comment(描述信息)、domain(cookie只是对指定的domain域可见,默认情况下cookie只会传输给设置这个cookie的server)、maxAge(cookie的最长可存活秒数,负数表示永远不会失效,0表示cookie会被删除)、path(指定那个path下的请求这个cookie才会被发送,包括它的子目录)、secure(这个cookie是否只在https请求中发送)、version(0表示netscape最初定义的cookie标准,1表示兼容RFC 2109,一般都是0以保持最大兼容性)、isHttpOnly(HttpOnly标识的cookie一般不应该暴露给客户端的脚本,以部分解决跨站点脚本攻击问题)字段。对浏览器,一般他们应该能为每个Web Server存储至少20个cookie,总共至少能处理300个cookie,以及至少4k大小。

     public Cookie[] getCookies();
    
     // 解析指定请求头的Date值,并转换成long值,如If-Modified-Since头。Jetty支持的Date格式有:EEE, dd MMM yyyy HH:mm:ss zzz; EEE, dd-MMM-yy HH:mm:ss等。
     public  long getDateHeader(String name);

     // 返回指定的请求头的值,没有该头,返回null,如果有多个相同名字的头,则返回第一个该头的值。name是大小写无关。
     public String getHeader(String name); 

     // 返回指定请求头的所有值
     public Enumeration<String> getHeaders(String name); 
    
     // 返回请求头的所有名称,有些Container会禁用该方法,此时返回null。
     public Enumeration<String> getHeaderNames();

     // 返回指定请求头的int值。
     public  int getIntHeader(String name);

     // 返回请求方法,如GET、POST、PUT等。该值在解析请求行结束后设置。
     public String getMethod();

     // 设置请求的额外path信息,该值在不同的地方会被设置为不同的值,如果请求的URI为: http://host:80/context/servlet/path/info如在HttpConnection中,其值为/context/servlet/path/info
    // 在ContextHandler的doScope中,其值被设置为/servlet/path/info;在ServletHandler的doScope方法中,其值被设置为/path/info,并设置ServletPath为/servlet。
    // 这里基于的假设为contextPath为/context,servletPath为/servlet,即在web.xml配置中Servlet相关的url-pattern为/servlet/*。
    // 如果没有/path/info后缀,则PathInfo为null,如果Servlet的path-pattern设置为/*,则ServletPath为"",对url-pattern为*.do类似的配置,pathInfo永远为null,servletPath则为/path/info.do的值;有些时候ServletPath的值也可能是Servlet Name的值。
    public String getPathInfo();
    public String getServletPath();

     // 返回pathInfo对应的在ServletContext下的真是Server路径,如果pathInfo为null,则返回null。
     public String getPathTranslated();

     // 返回当前请求所属的ContextPath。它在ContextHandler的doScope方法中或Dispatcher的forward方法中设置。
     public String getContextPath();
    
     // 返回当前请求的query字符串,如果设置了queryEncoding,使用该编码方式编码。
     public String getQueryString();

     // 返回请求的登陆用户,如果用户没有认证,则返回null。该信息从设置的Authentication实例中获取,如果其实例为Authentication.Defered,则需要先验证,然后返回获取UserIdentity,并从中获取Principal,而从Principal中可以获取用户名。
     public String getRemoteUser();

     // 验证当前请求的User是否在传入的Role中,即使用设置的Authentication实例验证,当前登陆的User所在的Roles中是否存在传入的RoleName。其中UserIdentity.Scope实例用于查找RoleName对应在Container使用的RoleName,如果没有这个映射则使用传入的RoleName本身,这个scope在ServletHandler的doScope方法中设置。这个映射在web.xml中的security-rol-ref(role-name->role-link)中设置。
     public  boolean isUserInRole(String role);

     // 返回当前登陆User的Principal实例,从设置的Authentication实例中获取,或者为null。
     public java.security.Principal getUserPrincipal();

     // 返回客户端指定的Session ID,它可以和Server的当前Session ID不同。客户端可以使用两种方式设置该值:Cookie和URL。默认先从Cookie中找,找不到再从URL中找。
    // 对Cookie方式,在web.xml的cookie-config/name中配置Session的Cookie Name(默认值为JSSESSIONID),找到该Cookie Name对应的Cookie值作为Requested Session ID
    // 对URL方式,在;<sessionIdPathParamName>=....[;#?/]之间的值作为Requested Session ID的值。其中sessionIdPathParamName可以通过web.xml的context-param,使用org.eclipse.jetty.servlet.SessionIdPathParameterName属性值配置,默认为jsessionid。

     public String getRequestedSessionId();
     public  boolean isRequestedSessionIdFromCookie();
     public  boolean isRequestedSessionIdFromURL();

     // 检查当前Requested Session Id是否valid,在Jetty中valid是指RequstedSessionId存在,并且和当前请求的Server Session的ClusterId相同,即他们的SessionId相同。
     public  boolean isRequestedSessionIdValid();    
    
     // 返回/contextPath/servletPath/pathInfo的值。对forward后请求,该值为forward后的URI。
     public String getRequestURI();
    
     // 返回getSchema()://getServerName():getPort()/getRequestURI(),对forward后请求,该值为forward后的URL。
     public StringBuffer getRequestURL();

     // 返回和当前请求相关联的HttpSession,如果没有关联的HttpSession,且create为true,则创建新的HttpSession实例。没有参数即create为true。
     public HttpSession getSession( boolean create);
     public HttpSession getSession();

     //使用Container定义的认证机制验证请求用户的合法性。在Jetty实现中,只是对Authentication.Deferred的Authentication类型进行验证,否则返回401 Unauthorized错误相应,并返回false。
     public  boolean authenticate(HttpServletResponse response)   throws IOException,ServletException;

     // 提供用户名和密码并交由Container对其进行认证。在Jetty实现中,只对Authentication.Deferred类型提供用户名和密码认证,否则抛出ServletException。
     public  void login(String username, String password)   throws ServletException;
    
     // 注销当前用户,并清理_authentication字段。
     public  void logout()  throws ServletException;

     // 对multipart/form-data请求类型,表示请求内容由多个部分组成,此时使用RFC1867来解析该内容到多个Part中。在Servlet中一个Part有自己的请求头和请求消息提,包含ContentType、Name、Headers、Size(已写入的大小)、InputStream等信息,它还提供了一个方法将请求内容写入指定的文件中,以及删除该内部文件。并提供MultipartConfigElement类来做相关的配置,如写文件时的位置Location;最大可上传的文件大小MaxFileSize;最大可包含的所有Part的请求大小MaxRequestSize;如果写入的数据超过配置的大小,则开始将数据写入文件中MaxFileSizeThreshold。该配置信息可以使用org.eclipse.multipartConfig属性设置,而Location信息可以使用javax.servlet.context.tempdir属性在ServletContext中设置,或这使用java.io.tmpdir中指定的值。在Jetty中使用MultiPartInputStream来表达并解析请求内容到多个Part(MultiPart)中。具体格式可以参考: http://blog.zhaojie.me/2011/03/html-form-file-uploading-programming.html
     public Collection<Part> getParts()  throws IOException, ServletException;
     public Part getPart(String name)  throws IOException, ServletException;
}
除了以上实现,Request还包含了一些额外的字段,如_timestamp在请求开始时设置,即解析请求头完成时;_dispatchTime在RequestLogHandler的handle方法,当Request是非Initial的状态下设置,即当前Request已经为Dispatched的状态;_handled表示该请求是否已经处理完成;

ServletResponse

ServletResponse是对Servlet响应消息的封装,其子接口HttpServletResponse则是对HTTP响应消息的封装, 

ServletResponse接口定义如下:
public  interface ServletResponse {
     // 设置与返回 消息体中的字符编码方式。如果没有设置,默认使用ISO-8559-1。其中setContentType和setLocale会隐式的设置该值,但是显示的设置会覆盖之前隐式的设置,而该值的设置也会影响ContentType的值。该值的设置必须在调用getWriter()方法之前,否则不会起作用。在set方法中,如果传入的charset为null,则清楚原来设置的值,并将原来的_mimeType值设置为Content-Type头;否则,更新characterEncoding的值,并更新contentType的属性以及Content-Type头(更新contentType中"charset="之后部分的值,或使用"mimeType; charset=<characterType>")。
     public  void setCharacterEncoding(String charset);
     public String getCharacterEncoding();

     // 设置响应消息的Content-Type头以及contentType字段的值,它会同时影响mimeType字段以及characterEncoding字段。如果type为null,则清除contentType、mimeType的值,移除Content-Type响应头,并且如果locale也为null,同时清除characterType值;否则,设置mimeType为";"之前的值,而characterEncoding的值为"charset="之后的值,如果没有"charset="之后的值,则是使用"charset=<characterType>"值拼接以设置Content-Type响应头。
     public  void setContentType(String type);
     public String getContentType();
    
     // 设置Locale的值,同时设置响应的Content-Language头。同时该set也会影响characterEncoding、mimeType和Content-Type响应头。其中characterEncoding从ContextHandler中的Locale到charset的映射中获取,即web.xml中的locale-encoding-mapping-list中定义,而对Content-Type的值只影响"charset="之后的值。
     public  void setLocale(Locale loc);
     public Locale getLocale();

     // 设置contentLength字段以及Content-Length响应消息头。如果当前写入的数据已经大于或等于设置的值,则该方法还会关闭当前的ServletOutputStream或Writer。
     public  void setContentLength( int len);  

     // 返回向客户端写数据的ServletOutputStream或PrintWriter。它们只能使用其中一个方法。在Jetty中使用HttpOutput内部封装HttpGenerator实例用于向Socket中写数据。
     public ServletOutputStream getOutputStream()  throws IOException;
     public PrintWriter getWriter()  throws IOException;    
    
     // 响应消息处理相关的Buffer操作,在Jetty中即为HttpGenerator中响应消息体的Buffer大小与刷新操作。设置BufferSize必须在写响应消息体之前。另外reset只是清除消息体的缓存,并不会清除响应状态码、响应头等信息,如果该方法调用时消息已经被commit,则抛出IllegalStateException。
     public  void setBufferSize( int size);
     public  int getBufferSize();
     public  void flushBuffer()  throws IOException;
     public  void resetBuffer();
    
    // 是否响应消息已经commit,即响应消息状态行和消息头已经发送给客户端。
     public  boolean isCommitted();

     // 清除所有的响应消息状态,所有已经设置的响应头(但是不包括Connection头),如果响应已经commit,则抛出IllegalStateException。
     public  void reset();
}
HttpServletResponse接口定义如下,它添加了一些Cookie、Header相关的操作:
public  interface HttpServletResponse  extends ServletResponse {
     // 向响应消息中添加一个Cookie实例。即添加"Set-Cookie"头。
     public  void addCookie(Cookie cookie);

     // 消息头操作:增删改查。一个相同名字的头可能会有多个条纪录,因而可以对应多个值。在Jetty实现中代理给HttpConnection中的responseFields字段。其中Date头的格式为:EEE, dd MMM yyyy HH:mm:ss 'GMT',对于String为值的设置来说,处于INCLUDE Dispatch状态下,只能设置org.eclipse.jetty.server.include.<HeaderName>的头。
     public  boolean containsHeader(String name);
     public  void setDateHeader(String name,  long date);
     public  void addDateHeader(String name,  long date);
     public  void setHeader(String name, String value);
     public  void addHeader(String name, String value);
     public  void setIntHeader(String name,  int value);
     public  void addIntHeader(String name,  int value);
     public String getHeader(String name); 
     public Collection<String> getHeaders(String name); 
     public Collection<String> getHeaderNames();

     // 编码传入的url,决定并添加是否需要在URL中加入Session ID信息以作为Session追踪。处于健壮性的考虑,所有Servlet产生的URL必须使用改方法编码,不然对不支持Cookie的浏览器将会失去Session信息。在实现中,如果Request使用Cookie作为Session追踪,则去除url中的sessionId信息;否则如果session存在并可用,则向url中添加session追踪信息,在"#"或"?"之前。
     public String encodeURL(String url);

     // 编码传入的url,用于sendRedirect方法中。在Jetty中改方法直接调用encodeURL()方法。
     public String encodeRedirectURL(String url);

     // 向客户端发送响应状态码和原因(如果有的话)。服务器会保留已经设置的cookie,但是会在必要情况下修改响应头。如果在web.xml中定义了响应的状态码到error page的映射,则该响应会被转发到那个错误页面中。在Jetty实现中,它清除Buffer信息,characterEncoding值,Expires、Last-Modified、Cache-Control、Content-Type、Content-Length头,设置响应状态和消息,对非204(No Content)、304(Not Modified)、206(Partial Content)、200(OK)的状态码(即允许有消息体),首先查找有没有注册的ErrorHandler ,如果有,向Request的属性中设置javax.servlet.error.status_code, javax.servlet.error.message, javax.servlet.error.request_uri, javax.servlet.error.servlet_name为相应的值(RequestDispatcher中定义的属性key),并调用ErrorHandler的handle方法;否则设置Cache-Control头为must-revalidate,no-cache,no-store,设置Content-Type头为text/html;charset=ISO-8859-1,并返回一个简单的错误页面包含状态码和消息原因。最后调用HttpConnection的completeResponse()方法以完成响应。
     public  void sendError( int sc, String msg)  throws IOException;
     public  void sendError( int sc)  throws IOException;

     // 发送客户端一个重定向的消息和URL,即设者响应状态码为302 Moved Temporary,在Location中包含要重定向目的地的URL,此时客户端会使用新的URL重新发送请求。如果location以"/"开头,表示它是绝对地址,否则为相应请求的相对地址,即最终解析成Request.getRequestURI()/location,location可以包含query信息。最后调用HttpConnection的completeResponse()方法以完成当前响应。
     public  void sendRedirect(String location)  throws IOException;
    
     // 设置响应状态码和状态描述信息。
     public  void setStatus( int sc);
     public  void setStatus( int sc, String sm);
     public  int getStatus();
}

相关文章
|
1月前
|
Java 计算机视觉
java实现人脸识别源码【含测试效果图】——Servlet层(FaceServlet)
java实现人脸识别源码【含测试效果图】——Servlet层(FaceServlet)
10 1
|
2月前
|
Java 应用服务中间件 数据库连接
Spring5源码(51)-Servlet知识点回顾以及SpringMVC分析入口
Spring5源码(51)-Servlet知识点回顾以及SpringMVC分析入口
36 0
|
3月前
|
前端开发 Java BI
Servlet+Jsp+JDBC实现房屋租赁管理系统(源码+数据库+论文+系统详细配置指导+ppt)
Servlet+Jsp+JDBC实现房屋租赁管理系统(源码+数据库+论文+系统详细配置指导+ppt)
|
3月前
|
前端开发 JavaScript Java
servlet+jsp实现小区门户网站后台管理系统(源码+数据库+文档)
servlet+jsp实现小区门户网站后台管理系统(源码+数据库+文档)
|
3月前
|
前端开发 JavaScript Java
基于servlet实现的日记本管理系统(源码+数据库+文档)
基于servlet实现的日记本管理系统(源码+数据库+文档)
|
3月前
|
Java 关系型数据库 MySQL
基于jsp+servlet+mysql框架的旅游管理系统【源码+数据库+报告】
基于jsp+servlet+mysql框架的旅游管理系统【源码+数据库+报告】
|
3月前
|
前端开发 JavaScript Java
基于servlet+jsp+mysql实现的工资管理系统【源码+数据库】
基于servlet+jsp+mysql实现的工资管理系统【源码+数据库】
|
4月前
|
Java 应用服务中间件 Maven
框架的优点(SpringBoot VS Servlet)
框架的优点(SpringBoot VS Servlet)
|
6月前
|
SQL 前端开发 Java
JSP网上订餐管理系统myeclipse开发sql数据库BS模式java编程servlet技术mvc框架
JSP 网上订餐管理系统是一套完善的web设计系统,对理解JSP java编程开发语言有帮助servlet技术mvc框架,系统具有完整的源代码和数据库,开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0,使用java语言开发,系统主要采用B/S模式开发。
39 0
|
22天前
|
Java
学校教师管理系统【JSP+Servlet+JavaBean】(Java课设)
学校教师管理系统【JSP+Servlet+JavaBean】(Java课设)
19 1