目录
百度定义:
Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
Servlet的声明周期 不会的自己去百度
特性
Servlet 3.1 | 2013年5月 | JavaEE 7 | Non-blocking I/O, HTTP protocol upgrade mechanism |
Servlet 3.0 | 2009年12月 | JavaEE 6, JavaSE 6 | Pluggability, Ease of development, Async Servlet, Security, File Uploading |
Servlet 2.5 | 2005年10月 | JavaEE 5, JavaSE 5 | Requires JavaSE 5, supports annotation |
Servlet 2.4 | 2003年11月 | J2EE 1.4, J2SE 1.3 | web.xml uses XML Schema |
Servlet 2.3 | 2001年8月 | J2EE 1.3, J2SE 1.2 | Addition of Filter |
Servlet 2.2 | 1999年8月 | J2EE 1.2, J2SE 1.2 | Becomes part of J2EE, introduced independent web applications in .war files |
Servlet 2.1 | 1998年11月 | 未指定 | First official specification, added RequestDispatcher, ServletContext |
Servlet 2.0 | JDK 1.1 | Part of Java Servlet Development Kit 2.0 | |
Servlet 1.0 | 1997年6月 |
新增功能
Servlet 2.2
:引入了 self-contained Web applications 的概念。
servlet 2.3
: 2000年10月份出来
Servlet API 2.3中最重大的改变是增加了 filters
Servlet 2.3 增加了 filters 和 filter chains 的功能。引入了 context 和 session listeners 的概念,当 context 或 session 被初始化或者被将要被释放的时候,和当向 context 或 session 中绑定属性或解除绑定的时候,可以对类进行监测。
servlet 2.4
: 2003年11月份推出
Servlet 2.4 加入了几个引起关注的特性,没有特别突出的新内容,而是花费了更多的功夫在推敲和阐明以前存在的一些特性上,对一些不严谨的地方进行了校验。
Servlet 2.4 增加了新的最低需求,新的监测 request 的方法,新的处理 response 的方法,新的国际化支持,RequestDispatcher 的几个处理,新的 request listener 类,session 的描述,和一个新的基于 Schema 的并拥有 J2EE 元素的发布描述符。这份文档规范全面而严格的进行了修订,除去了一些可能会影响到跨平台发布的模糊不清的因素。总而言之,这份规范增加了四个新类,七个新方法,一个新常量,不再推荐使用一个类。
注意:改为 Schema 后主要加强了两项功能:
(1) 元素不依照顺序设定;
(2) 更强大的验证机制。
主要体现在:
a.检查元素的值是否为合法的值
b.检查元素的值是否为合法的文字字符或者数字字符
c.检查 Servlet, Filter, EJB-ref 等等元素的名称是否唯一
2.新增 Filter 四种设定:REQUEST、FORWARD、INCLUDE 和 ERROR。
3.新增 Request Listener、Event和Request Attribute Listener、Event。
4.取消 SingleThreadModel 接口。当 Servlet 实现 SingleThreadModel 接口时,它能确保同时间内,只能有一个 thread 执行此 Servlet。
5.<welcome-file-list>可以为Servlet。
6.ServletRequest接口新增一些方法。
public String getLocalName();
public String getLocalAddr();
public int getLocalPort();
public int getRemotePort()
Servlet 2.5
2005 年 9 月发布 Servlet 2.5
Servlet 2.5 一些变化的介绍:
1) 基于最新的 J2SE 5.0 开发的。
2) 支持 annotations 。
3) web.xml 中的几处配置更加方便。
4) 去除了少数的限制。
5) 优化了一些实例
Servlet 的各个版本对监听器的变化有:
(1) Servlet 2.2 和 jsp1.1
新增Listener:HttpSessionBindingListener
新增Event: HttpSessionBindingEvent
(2) Servlet 2.3 和 jsp1.2
新增Listener:ServletContextListener,ServletContextAttributeListener
,HttpSessionListener,HttpSessionActivationListener,HttpSessionAttributeListener
新增Event: ServletContextEvent,ServletContextAttributeEvent,HttpSessionEvent
(3) Servlet 2.4 和 jsp2.0
新增Listener:ServletRequestListener,ServletRequestAttribureListener
新增Event: ServletRequestEvent,ServletRequestAttributeEvent
Servlet 3.0
Servlet 3.0 作为 Java EE 6 规范体系中一员[1] ,随着 Java EE 6 规范一起发布。该版本在前一版本(Servlet 2.5)的基础上提供了若干新特性用于简化 Web 应用的开发和部署。其中有几项特性的引入让开发者感到非常兴奋,同时也获得了 Java 社区的一片赞誉之声:[2]
-
异步处理支持:有了该特性,Servlet 线程不再需要一直阻塞,直到业务处理完毕才能再输出响应,最后才结束该 Servlet 线程。在接收到请求之后,Servlet 线程可以将耗时的操作委派给另一个线程来完成,自己在不生成响应的情况下返回至容器。针对业务处理较耗时的情况,这将大大减少服务器资源的占用,并且提高并发处理速度。[2]
-
新增的注解支持:该版本新增了若干注解,用于简化 Servlet、过滤器(Filter)和监听器(Listener)的声明,这使得 web.xml 部署描述文件从该版本开始不再是必选的了。[2]
-
可插性支持:熟悉 Struts2 的开发者一定会对其通过插件的方式与包括 Spring 在内的各种常用框架的整合特性记忆犹新。将相应的插件封装成 JAR 包并放在类路径下,Struts2 运行时便能自动加载这些插件。现在 Servlet 3.0 提供了类似的特性,开发者可以通过插件的方式很方便的扩充已有 Web 应用的功能,而不需要修改原有的应用。[2]
Servlet 4.0草案
从3.1到4.0将是对Servlet 协议的一次大改动,而改动的关键之处在于对HTTP/2的支持。HTTP2将是是继上世纪末HTTP1.1协议规范化以来首个HTTP协议新版本,相对于HTTP1.1,HTTP2将带来许多的增强。在草案提议中,Shing Wai列举出了一些HTTP2的新特性,而这些特性也正是他希望在Servlet 4.0 API中实现并暴露给用户的新功能,这些新特性如下:[3]
1.请求/响应复用(Request/Response multiplexing)
2.流的优先级(Stream Prioritization)
3.服务器推送(Server Push)
4.HTTP1.1升级(Upgrade from HTTP 1.1)[3]
为了简化开发流程,Servlet 3.0 引入了注解(annotation),这使得 web 部署描述符 web.xml 不再是必须的选择。
Pluggability可插入性
当使用任何第三方的框架,如 Struts,JSF 或 Spring,我们都需要在 web.xml 中添加对应的 Servlet 的入口。这使得 web 描述符笨重而难以维护。Servlet3.0 的新的可插入特性使得 web 应用程序模块化而易于维护。通过 web fragment 实现的可插入性减轻了开发人员的负担,不需要再在 web.xml 中配置很多的 Servlet 入口。
Asynchronous Processing 异步处理
另外一个显著的改变就是 Servlet 3.0 支持异步处理,这对 AJAX 应用程序非常有用。当一个 Servlet 创建一个线程来处理某些请求的时候,如查询数据库或消息连接,这个线程要等待直到获得所需要的资源才能够执行其他的操作。异步处理通过运行线程执行其他的操作来避免了这种阻塞。
Apart from the features mentioned here, several other enhancements have been made to the existing API. The sections towards the end of the article will explore these features one by one in detail.
除了这些新特性之外, Servlet 3.0对已有的 API 也做了一些改进,在本文的最后我们会做介绍。
Annotations in Servlet Servlet中使用注解
Servlet 3.0 的一个主要的改变就是支持注解。使用注解来定义 Servlet 和 filter 使得我们不用在 web.xml 中定义相应的入口。
@WebServlet
@WebServlet 用来定义 web 应用程序中的一个 Servlet。这个注解可以应用于继承了 HttpServlet。这个注解有多个属性,例如 name,urlPattern, initParams,我们可以使用者的属性来定义 Servlet 的行为。urlPattern 属性是必须指定的。
Servlet和容器之间是怎么工作的
https://www.cnblogs.com/whgk/p/6399262.html
常见容器
- Tomcat,
- Jetty
- resin
- Oracle Application server
- WebLogic Server
- Glassfish
- Websphere
- JBoss
(提供了 Servlet 功能的服务器,叫做 Servlet 容器。对 web 程序来说,Servlet 容器的作用就相当于桌面程序里操作系统的作用,都是提供一些编程基础设施)
Servlet 3.0 出现在jsr 315
ServletApi的讲解
api结构
Servlet API中共有5个包,约113个类或者接口
javax.servlet
javax.servlet.http
javax.servlet.jsp
javax.servlet.annotation
javax.servlet.descriptor
Servlet API的层次结构图
Servlet接口
- package javax.servlet;
- import java.io.IOException;
- // Referenced classes of package javax.servlet:
- // ServletException, ServletConfig, ServletRequest, ServletResponse
- public interface Servlet
- {
- public abstract void init(ServletConfig servletconfig)
- throws ServletException;
- public abstract ServletConfig getServletConfig();
- public abstract void service(ServletRequest servletrequest, ServletResponse servletresponse)
- throws ServletException, IOException;
- public abstract String getServletInfo();
- public abstract void destroy();
- }
重要方法
init() 在容器启动时调用(当laod-onstart-up设置为负或者不设置,会在Servlet第一次用到才被调用),只会调用一次,接收一个ServletConfig由容器传入,在xml定义的init-param中的配置文件由ServletConfig保存
getServletConfig方法获取ServletConfig
service方法用于处理具体的一个请求
getServletInfo获取一些Servlet的相关信息,默认返回空字符串 需要自己实现
destory关闭服务器释放资源,只调用一次
==================================
StandardWrapper本身包含配置信息门面的Facade类
ServletConfig 包含了name,servletContent
ServletContent保存了Application级别的属性 setAttribute完成
用途传递初始化参数
GnericServlet
是Servlet默认实现
主要3件事实现了ServletConfig接口,提供了无参init方法 ,提供了log方法
主要完成了以下工作
将init方法中的ServletConfig赋值给一个类级变量,在里面将config设置给了内部config,然后调用了无参的init方法,而且使它可以通过调用getServletConfig来获取config。
其中init为模板方法在子类中可以通过覆盖它完成自己定义的初始化
为Servlet接口中的所有方法提供默认实现。
提供方法来包装ServletConfig中的方法。
但由于一般而言,servlet均为HttpServlet,因此GenericServlet并不常用,主要使用HttpServlet。
GericServlet提供了2个记录log方法
1记录日志
2.记录异常
具体是通过传给ServletContent的日志来实现 因为我们一般有自己日志 所以用的不多
GernicServlet 与协议无关
HttpServlet 作用是将不同的请求方式路由到不同的处理方法
用Http协议实现的Servlet基类,其实在SpringMvc中的DispatcherServlet就是继承了HttpServlet
先查看源代码
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.ResourceBundle;
import javax.servlet.*;
// Referenced classes of package javax.servlet.http:
// NoBodyResponse, HttpServletRequest, HttpServletResponse
public abstract class HttpServlet extends GenericServlet
implements Serializable
{
public HttpServlet()
{
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if(protocol.endsWith("1.1"))
resp.sendError(405, msg);
else
resp.sendError(400, msg);
}
protected long getLastModified(HttpServletRequest req)
{
return -1L;
}
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
NoBodyResponse response = new NoBodyResponse(resp);
doGet(req, response);
response.setContentLength();
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if(protocol.endsWith("1.1"))
resp.sendError(405, msg);
else
resp.sendError(400, msg);
}
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_put_not_supported");
if(protocol.endsWith("1.1"))
resp.sendError(405, msg);
else
resp.sendError(400, msg);
}
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_delete_not_supported");
if(protocol.endsWith("1.1"))
resp.sendError(405, msg);
else
resp.sendError(400, msg);
}
private Method[] getAllDeclaredMethods(Class c)
{
if(c.equals(javax/servlet/http/HttpServlet))
return null;
Method parentMethods[] = getAllDeclaredMethods(c.getSuperclass());
Method thisMethods[] = c.getDeclaredMethods();
if(parentMethods != null && parentMethods.length > 0)
{
Method allMethods[] = new Method[parentMethods.length + thisMethods.length];
System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length);
System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length);
thisMethods = allMethods;
}
return thisMethods;
}
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
Method methods[] = getAllDeclaredMethods(getClass());
boolean ALLOW_GET = false;
boolean ALLOW_HEAD = false;
boolean ALLOW_POST = false;
boolean ALLOW_PUT = false;
boolean ALLOW_DELETE = false;
boolean ALLOW_TRACE = true;
boolean ALLOW_OPTIONS = true;
for(int i = 0; i < methods.length; i++)
{
Method m = methods[i];
if(m.getName().equals("doGet"))
{
ALLOW_GET = true;
ALLOW_HEAD = true;
}
if(m.getName().equals("doPost"))
ALLOW_POST = true;
if(m.getName().equals("doPut"))
ALLOW_PUT = true;
if(m.getName().equals("doDelete"))
ALLOW_DELETE = true;
}
String allow = null;
if(ALLOW_GET && allow == null)
allow = "GET";
if(ALLOW_HEAD)
if(allow == null)
allow = "HEAD";
else
allow = (new StringBuilder()).append(allow).append(", HEAD").toString();
if(ALLOW_POST)
if(allow == null)
allow = "POST";
else
allow = (new StringBuilder()).append(allow).append(", POST").toString();
if(ALLOW_PUT)
if(allow == null)
allow = "PUT";
else
allow = (new StringBuilder()).append(allow).append(", PUT").toString();
if(ALLOW_DELETE)
if(allow == null)
allow = "DELETE";
else
allow = (new StringBuilder()).append(allow).append(", DELETE").toString();
if(ALLOW_TRACE)
if(allow == null)
allow = "TRACE";
else
allow = (new StringBuilder()).append(allow).append(", TRACE").toString();
if(ALLOW_OPTIONS)
if(allow == null)
allow = "OPTIONS";
else
allow = (new StringBuilder()).append(allow).append(", OPTIONS").toString();
resp.setHeader("Allow", allow);
}
protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String CRLF = "\r\n";
String responseString = (new StringBuilder()).append("TRACE ").append(req.getRequestURI()).append(" ").append(req.getProtocol()).toString();
for(Enumeration reqHeaderEnum = req.getHeaderNames(); reqHeaderEnum.hasMoreElements();)
{
String headerName = (String)reqHeaderEnum.nextElement();
responseString = (new StringBuilder()).append(responseString).append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName)).toString();
}
responseString = (new StringBuilder()).append(responseString).append(CRLF).toString();
int responseLength = responseString.length();
resp.setContentType("message/http");
resp.setContentLength(responseLength);
ServletOutputStream out = resp.getOutputStream();
out.print(responseString);
out.close();
}
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if(method.equals("GET"))
{
long lastModified = getLastModified(req);
if(lastModified == -1L)
{
doGet(req, resp);
} else
{
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if(ifModifiedSince < (lastModified / 1000L) * 1000L)
{
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else
{
resp.setStatus(304);
}
}
} else
if(method.equals("HEAD"))
{
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else
if(method.equals("POST"))
doPost(req, resp);
else
if(method.equals("PUT"))
doPut(req, resp);
else
if(method.equals("DELETE"))
doDelete(req, resp);
else
if(method.equals("OPTIONS"))
doOptions(req, resp);
else
if(method.equals("TRACE"))
{
doTrace(req, resp);
} else
{
String errMsg = lStrings.getString("http.method_not_implemented");
Object errArgs[] = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
private void maybeSetLastModified(HttpServletResponse resp, long lastModified)
{
if(resp.containsHeader("Last-Modified"))
return;
if(lastModified >= 0L)
resp.setDateHeader("Last-Modified", lastModified);
}
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
try
{
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
}
catch(ClassCastException e)
{
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
private static final String METHOD_DELETE = "DELETE";
private static final String METHOD_HEAD = "HEAD";
private static final String METHOD_GET = "GET";
private static final String METHOD_OPTIONS = "OPTIONS";
private static final String METHOD_POST = "POST";
private static final String METHOD_PUT = "PUT";
private static final String METHOD_TRACE = "TRACE";
private static final String HEADER_IFMODSINCE = "If-Modified-Since";
private static final String HEADER_LASTMOD = "Last-Modified";
private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
}
重点关注如何处理请求
工作 主要重写了service方法
在service方法中
1.将ServletResponse和ServletRequest转化为HttpServletResponse和HttpServletRequest,源码中的实现如下
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
try
{
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
}
catch(ClassCastException e)
{
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
2.根据Http的请求类型不同将请求路由到不同的处理方法。源码中的实现如下
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if(method.equals("GET"))
{
long lastModified = getLastModified(req);
if(lastModified == -1L)
{
doGet(req, resp);
} else
{
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if(ifModifiedSince < (lastModified / 1000L) * 1000L)
{
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else
{
resp.setStatus(304);
}
}
} else
if(method.equals("HEAD"))
{
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else
if(method.equals("POST"))
doPost(req, resp);
else
if(method.equals("PUT"))
doPut(req, resp);
else
if(method.equals("DELETE"))
doDelete(req, resp);
else
if(method.equals("OPTIONS"))
doOptions(req, resp);
else
if(method.equals("TRACE"))
{
doTrace(req, resp);
} else
{
String errMsg = lStrings.getString("http.method_not_implemented");
Object errArgs[] = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
3.具体的方法是doXXX的结构,这些都是模板方法,如果没有子类实现抛出异常,
另外还发现
if(method.equals("GET"))
{
long lastModified = getLastModified(req);
if(lastModified == -1L)
{
doGet(req, resp);
} else
{
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if(ifModifiedSince < (lastModified / 1000L) * 1000L)
{
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else
{
resp.setStatus(304);
}
}
}
在调用doGet方法之前还对是否过期做了检查,如果没有过期直接返回304状态码并使用缓存
if(method.equals("HEAD"))
{
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
}
doHead调用了doGet的请求,然后返回空body的Response
下面在分析下内部的doXXX方法
protected void doXXX(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_xxx_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
发现doXXX()方法只是判断协议类型,然后抛出相应的异常,其他什么都没做。所以,在实现自己的Servlet时,需要重写这些方法,以符合自己的需求。一般不需要重写service方法。
HTTP的请求方式包括DELETE,GET,OPTIONS,POST,PUT和TRACE,在HttpServlet类中分别提供了相应的服务方法,它们是doDelete(),doGet(),doOptions(),doPost(),doPut()和doTrace().
doOptions和doTrace正常不使用主要用来做一些调试工作,由于doOptions和doTrace功能非常固定,所以提供了默认实现
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
Method methods[] = getAllDeclaredMethods(getClass());
boolean ALLOW_GET = false;
boolean ALLOW_HEAD = false;
boolean ALLOW_POST = false;
boolean ALLOW_PUT = false;
boolean ALLOW_DELETE = false;
boolean ALLOW_TRACE = true;
boolean ALLOW_OPTIONS = true;
for(int i = 0; i < methods.length; i++)
{
Method m = methods[i];
if(m.getName().equals("doGet"))
{
ALLOW_GET = true;
ALLOW_HEAD = true;
}
if(m.getName().equals("doPost"))
ALLOW_POST = true;
if(m.getName().equals("doPut"))
ALLOW_PUT = true;
if(m.getName().equals("doDelete"))
ALLOW_DELETE = true;
}
String allow = null;
if(ALLOW_GET && allow == null)
allow = "GET";
if(ALLOW_HEAD)
if(allow == null)
allow = "HEAD";
else
allow = (new StringBuilder()).append(allow).append(", HEAD").toString();
if(ALLOW_POST)
if(allow == null)
allow = "POST";
else
allow = (new StringBuilder()).append(allow).append(", POST").toString();
if(ALLOW_PUT)
if(allow == null)
allow = "PUT";
else
allow = (new StringBuilder()).append(allow).append(", PUT").toString();
if(ALLOW_DELETE)
if(allow == null)
allow = "DELETE";
else
allow = (new StringBuilder()).append(allow).append(", DELETE").toString();
if(ALLOW_TRACE)
if(allow == null)
allow = "TRACE";
else
allow = (new StringBuilder()).append(allow).append(", TRACE").toString();
if(ALLOW_OPTIONS)
if(allow == null)
allow = "OPTIONS";
else
allow = (new StringBuilder()).append(allow).append(", OPTIONS").toString();
resp.setHeader("Allow", allow);
}
doOptions返回所有支持的处理数据类型的集合,正常情况下可以禁用
protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String CRLF = "\r\n";
String responseString = (new StringBuilder()).append("TRACE ").append(req.getRequestURI()).append(" ").append(req.getProtocol()).toString();
for(Enumeration reqHeaderEnum = req.getHeaderNames(); reqHeaderEnum.hasMoreElements();)
{
String headerName = (String)reqHeaderEnum.nextElement();
responseString = (new StringBuilder()).append(responseString).append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName)).toString();
}
responseString = (new StringBuilder()).append(responseString).append(CRLF).toString();
int responseLength = responseString.length();
resp.setContentType("message/http");
resp.setContentLength(responseLength);
ServletOutputStream out = resp.getOutputStream();
out.print(responseString);
out.close();
}
doTrace是用来远程诊断服务器的,它会将接收到的header原封不动的返回
但最好还是把doTrace和doOptions禁用掉,防止黑客利用安全漏洞。
但是在SpringMVC将请求合并到同一的一个方法中进行处理
手都写麻了 ,未完待续。
欢迎关注我的个人订阅号,我会推送更好的文章给大家