by:lubingyanghtml
Servlet就是一个普通的类,只不过这个类可以接受和处理请求,而且作出响应。提到Servlet就绕不开Servlet容器,那么什么又是Servlet容器呢?通俗的讲就是实现Servlet标准管理辅助Servlet类工做的工具。Servlet和Servlet容器在我看来就是子弹和枪的关系,经过对标准化接口的实现互相配合,彼此依存又独立发展。在大部分的状况下咱们又称Servlet容器为服务器,经常使用的有Tomcat等。java
HTTP(超文本传输协议):是互联网通讯的基础,属于 TCP/IP 模型中的应用层协议,当浏览器与服务器进行互相通讯时,须要先创建TCP 链接,以后服务器才会接收浏览器的请求信息(request),当接收到信息以后,服务器返回相应的信息(response)。最后浏览器接受对服务器的信息应答后,对这些数据进行解释执行(解析HTML文件和各类资源进行展现)。web
HTTP是一个无状态的链接协议。面试
所谓无状态:浏览器
根据早期的HTTP协议,每次request-reponse时,都要从新创建TCP链接。TCP链接每次都从新创建,因此服务器没法知道上次请求和本次请求是否来自于同一个客户端。所以,HTTP通讯是无状态(stateless)的。服务器认为每次请求都是一个全新的请求,不管该请求是否来自同一地址。如今,虽然HTTP协议容许TCP链接复用,以节省创建链接所耗费的时间,但无状态的特性依旧被保留。安全
为了迎接HTTP的到来,首先咱们须要有一个Servlet类,而且告诉Servlet容器本身的存在,这两个准备步骤就是建立Servlet类和写入配置文件。服务器
正如上文所讲,类和Servlet容器之间的配合是经过接口实现的,一个类只须要实现特定的接口,就能够称为一个Servlet类,而且可以被Servlet所接受,嗯,想来这就是接口的解耦和。cookie
准备一个Servlet类session
拥有一个Servlet类的三种方案mybatis
在直接实现或者间接实现Servlet接口以后咱们须要重写其中的service方法,到此Servlet就准备好了。
写入配置文件
配置文件是一个固定的写法,主要就是为了告诉Servlet容器本身在哪
<servlet>
<servlet-name>自定义Servlet的别名</servlet-name>
<servlet-class>Servlet类的全类名</servlet-class>
</servlet>
<servlet-mapping>
<servelt-name>自定义Servlet的别名</servelt-name>
<url-pattern>自定义路径</url-pattern>
</servlet-mapping>
复制代码
Servlet容器开启服务以后就能够迎接request的到来了,当这个HTTP请求到达Servlet容器(以Tomcat为例)的时候,Tomcat看到有HTTP来,就把它带到要去的那个地方(项目名),到了地点以后,Tomcat会拿出花名册(web.xml)让request挑一个(0.0)。
结果,不用挑有指定的,那就好办了。
Tomcat在部署文件中找 servlet-mapping 中与之匹配的 url-pattern,根据这个 url-pattern 的 servlet-name 映射到真正的 servlet-class ,而后调用相应的 Servlet 类。
扩展内容:xml
xml全称是Extensible Markup Language可扩展标记语言,看到这个不免会想起来HTML,他们有什么关系呢?为何有了HTML语言还要xml语言呢?
认真的讲他们最大的关系就是都以ml结尾了,哈哈,开个玩笑。
HTML咱们是很熟悉的,在使用的时候不难发现其中的标签都是定义好的,全世界的HTML文档用的是同一套标记的语法。
而xml更具备个性化,其中的标签不只能够用别人的定义好的,也能够本身定义。书写一个xml有两个相关的规则,一个是标签规则,另外一个就是校检规则,校检规则是用来告诉程序标签之间的规则,这个东西被称之为文档类型定义 Document Type Definition , 简称 DTD 这两个规则都是能够自定义的(所谓扩展),因此咱们在书写不一样的xml文件的时候,会发现标签规则是不同的。
从这些层面上来讲HTML语言也能够说是xml中的一种,HTML5就是最新的校检规则(不知道这么理解有没有问题???)
<!-- 咱们不难发现不少xml文档的文档声明中都有声明其文档符合的校检规则 --> <!-- web.xml --> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> XML Schema是dtd的改进版 <!-- mybatis-config.xml --> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > 复制代码
经过以上的步骤Tomcat就找到了HTTP想要见到的那个Servlet了,可是这个类也许准备好了,也许没有,咱们假定这个request是第一次来。这时候就开始了Servlet的生命周期了。
由于是第一次请求,Tomcat会调用Servlet类的无参构造方法,建立这个Servlet的对象。
以后初始化,会调用init方法,这个方法会对Servlet类作一些初始化的工做,须要注意的这个方法在Servlet的一辈子中只会执行这么一次。像初始化这么重要的事儿只进行一次是有现实意义的,毕竟若是能够屡次的话,我早就一米八了。
初始化以后一个Servlet就正式的进入服务状态能够接客了,这时候就会调用service方法,接受HTTP的request,并对这个请求作一些服务项目,剪个头发之类啊,最后再把面目全非的请求送走,不,这时候应该叫响应response。据说每次剪头发都像整容,惋惜很久没有剪过头发了。
通过第一个请求以后,再有HTTP过来的时候,Servlet会直接调用service方法为其服务,毕竟谁一生也不能接一个客户初始化一次吧。
最后当服务关闭的时候,会销毁这个对象,在销毁前会调用destroy方法。
写到会话跟踪要先从HTTP开始提及,在以前咱们说过HTTP是无状态的。由于其无状态的特性,服务器不能以状态来区分和管理请求和响应,并且一次请求响应以后就会断开链接,因此服务器也不须要保存状态信息,虽然这样简单不占资源,适用性广,可是不利之处在于咱们没有办法根据HTTP自己对请求作一些区分。
因此为了在保留无状态协议这个特征的同时又解决相似记录状态的矛盾问题,出现了Cookie。
从上图咱们知道,有几个关键性的步骤是须要咱们来作的:
建立Cookie
//参数是cookie的标记和值,必须是英文
Cookie cookie = new Cookie(flag,value);
复制代码
响应信息中加上Cookie
response.addCookie(cookie);
复制代码
再次请求到来的时候检查Cookie
//获取request中全部的cookie信息
Cookies[] cookies = request.getCookies();
//遍历检查cookie
if(cookies != null){
for(Cookie c : cookies){
String name = c.getName();
String value = c.getValue();
}
}
复制代码
注
cookie是有有效期的,通常会在浏览器关闭的时候自动清空
设置cookie有效期,调用方法setMaxAge(60)
cookie中的数据是不安全的,毕竟保存到本地,能够显式查看
session是服务器为每个浏览器创建的私人存储空间,其中(session做用域)能够存储浏览器的属性和一些配置信息,当浏览器拿到session以后(没有更换持有的session),在不一样的Servlet之间跳转的时候,能够随时取出放在做用域中的数据。
上图是session的基本实现原理,咱们能够看到session是经过cookie来实现的,具体的步骤是这样的:
浏览器把登陆信息放入HTTP请求报文的实体部分,一般是以POST 方法把请求发送给服务器
服务器建立session,并将用户信息和session进行绑定记录在服务器,而后把处理好的session放入cookie中随着响应发给浏览器。
浏览器收到服务器响应的带有session信息的cookie时,会将cookie存在本地,下次请求的时候自动携带,服务器会经过接受其中的session对用户进行验证。
从本质上来说,区别只有两点:
那么咱们常提到的区别是从哪里来的呢?
从解释上面的区别开始。
早期的HTTP协议只有GET方法。根据HTTP协议,服务器接收到GET请求后,会将特定资源响应给浏览器,GET方法是经过改写URL实现的,在URL后面加上要传递的数据(格式是URL?key=value&key=value......)。因此在使用GET方法请求资源的时候,请求每每是没有主体的。
那么问题来了,什么是主体?
所谓主体就是request的报文主体,咱们知道HTTP请求的报文格式(响应雷同)是这样的
l 起始行
l 头信息
l 主体
GET方法的请求报文信息通常只有起始行和头信息,以下:
<!-- 拼接后的url -->
http://localhost:8801/zhibaxm/servlet/LoginAction?username=%E5%BE%90%E9%80%9A%E8%BE%BE&pwd=123
<!-- 请求头 -->
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Host:localhost:8801
Origin:http://localhost:8801
Referer:http://localhost:8801/zhibaxm/login.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
复制代码
而对于POST方法,URL再也不被改写,相关的表单数据会位于http请求的主体。以下:
<!-- url -->
http://localhost:8801/zhibaxm/servlet/LoginAction
<!-- 请求头 -->
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Host:localhost:8801
Origin:http://localhost:8801
Referer:http://localhost:8801/zhibaxm/login.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
<!-- POST的主体信息 -->
username=%E5%BE%90%E9%80%9A%E8%BE%BE&pwd=123
复制代码
咱们知道每个请求都是能够有三部分的:起始行,请求头,主体,也就是说,GET和POST的区别不是语法上的,而是规范上的,简单的说就是,你在使用POST的时候若是把参数写在url上也是没有问题的。
可是,咱们在使用中确实有不少的不一样,咋回事儿呢?这些区别并非语法自己的不一样,而是因为浏览器和服务器差别形成的使用上的区别,例如:大部分浏览器的url长度限制在2K个字节,而大部分服务器最多处理64K大小的url。在使用GET方法时,若是你在报文主体写入了数据,那么不一样服务器的处理方式也是不一样的,有些服务器会接受有些不会。
形成区别的缘由更多不是来自语法自己,而是不一样浏览器服务器的限制。
扯完了这些,补充一下应用上区别,毕竟遇到面试的时候,使用上的差异也是不可以忘记的,使用上的区别以下:
GET | POST |
---|---|
只能够接受字符串 | 没有限制 |
不安全 | 相对安全 |
有长度限制 | 没有长度限制 |
... | ... |