Session和浏览器之间技术内幕
作用域总结【总要】
HttpServletRequest:一次请求,请求响应之前有效
HttpSession:一次会话开始,浏览器不关闭或不超时之前有效
ServletContext:服务器启动开始,服务器停止之前有效
ps:关系到数据的传递
Session和Cookie的区别和使用范围
1、描述Cookie和Session的区别
①存在的位置:
cookie 存在于客户端,临时文件夹中; session存在于服务器的内存中,一个session域对象为一个用户浏览器服务
②安全性
cookie是以明文的方式存放在客户端的,安全性低,可以通过一个加密算法进行加密后存放; session存放于服务器的内存中,所以安全性好
③网络传输量
cookie会传递消息给服务器; session本身存放于服务器,不会有传送流量
④生命周期(以20分钟为例)
cookie的生命周期是累计的,从创建时,就开始计时,20分钟后,cookie生命周期结束;
session的生命周期是间隔的,从创建时,开始计时如在20分钟,没有访问session,那么session生命周期被销毁。但是,如果在20分钟内(如在第19分钟时)访问过session,那么,将重新计算session的生命周期。关机会造成session生命周期的结束,但是对cookie没有影响
⑤访问范围
cookie为多个用户浏览器共享; session为一个用户浏览器独享
2、session产生的session_id放在cookie里面,如果用户把cookie禁止掉,是不是session也不能用了呢?
禁止掉cookie后,理论上session是不可以用,不过通过其他的方式来获得这个sessionid,比如,可以跟在url的后面,或者以表单的形势提交到服务器端。从而使服务器端了解客户端的状态。
3、为什么说session 比cookie更安全?
真正的cookie存在于客户端硬盘上的一个文本文件,如果两者一样的话,只要cookie就好了,让客户端来分提服务器的负担,并且对于用户来说又是透明的。但实际上不是。
session的sessionID是放在cookie里,要想功破session的话,得分两步:
第一要得到sessionID。攻破cookie后,你要得到sessionID,sessionID是要有人登录,或者启动session_start才会有,你不知道什么时候会有人登录。
第二取有效sessionID。sessionID是加密的,第二次session_start的时候,前一次的sessionID就没有用了,session过期时sessionid也会失效,想在短时间内功破加了密的 sessionID很难。session是针对某一次通信而言,会话结束session也就随着消失了。
使session失效的方法:
1.关闭tomcat 2.重启web应用 3.session时间到 4.无效的session
4、cookie和session原理?
cookie采用的是客户端的会话状态的一种储存机制。它是服务器在本地机器上存储的小段文本或者是内存中的一段数据,并随每一个请求发送至同一个服务器。
session是一种服务器端的信息管理机制,它把这些文件信息以文件的形式存放在服务器的硬盘空间上
所谓session你可以这样理解:当你与服务端进行会话时,比如说登陆成功后,服务端会为你开壁一块内存区间,用以存放你这次会话的一些内容,比如说用户名之类的。那么就需要一个东西来标志这个内存区间是你的而不是别人的,这个东西就是session id(jsessionid只是tomcat中对session id的叫法,在其它容器里面,不一定就是叫jsessionid了。),而这个内存区间你可以理解为session。
然后,服务器会将这个session id发回给你的浏览器,放入你的浏览器的cookies中(这个cookies是内存cookies,跟一般的不一样,它会随着浏览器的关闭而消失)。
之后,只有你浏览器没有关闭,你每向服务器发请求,服务器就会从你发送过来的cookies中拿出这个session id,然后根据这个session id到相应的内存中取你之前存放的数据。
但是,如果你退出登陆了,服务器会清掉属于你的内存区域,所以你再登的话,会产生一个新的session了。
JavaWeb三大组件之一Filter【过滤器】
什么是过滤器
Filiter也称为过滤器,它是Servlet技术中心的一个技术分支,WEB开发人员可以用过 Filter技术,对WEB服务器进行管理所有WEB资源
**【JSP、Servlet、静态html、传递信息】**有效拦截和过滤,从而实现某些特殊的功能,例如对所有Service层的代码添加try-catch,实现URL级别的权限控制、过滤敏感词汇,压缩响应等等一些功能
Servelt API中提供了一个Filter接口,开发Web应用时,如果编写的Java类实现了这个接口,则把这个Java类称为过滤器类【即Filter类】,就可以通过Filter技术,实现对某个目标资源进行拦截过滤
ps:JavaWEB的三大组件【Servlet程序、Filter过滤器、Listener监听器】
Filter过滤器是JavaEE的规范是一个接口,Filter过滤器它的作用是:拦截请求,过滤响应
如果编写Filter过滤器
步骤:
1.创建一个Java类型,实现Filter接口
2.重写doFilter方法【核心处理的逻辑】
3.设置拦截的URL【那些URL需要过滤】
简单演示:
步骤1:先提供一个Servlet让Filter进行过滤
package com.qfedu.Filter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//演示让Filter过滤
@WebServlet(name = "Servlet1",value="/servlet1")
public class Servlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我的访问是通过Filter过滤的");
}
}
步骤2:编写衣一个Filter类完成过滤方式
package com.qfedu.Filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 过滤路径:
* 需要注意: 过滤器的作用是在【客户端访问服务器servlet时 提供一种过滤方式】
* 换句话说:客户端访问服务器Servlet时不是直接访问Servlet,而是通过访问过滤器【满足某项需求】之后在访问Servlet
* 所以使用注解配置路径的时候,路径配置的是【过滤的资源路径】
* filter这个类不需要手动访问,访问被Filter标注的资源自动调用
*/
@WebFilter("/servlet1")
public class MyFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化......init...."+filterConfig);
}
/**
* 过滤器核心方法,这个方法是对过滤逻辑的实现,主要实现拦截过滤使用
* @param servletRequest
* @param servletResponse
* 这两个参数是基本的请求和响应【因为现实是服务器程序,一次完成会话 需要有请求和响应,过滤器过滤的这个请求和响应】
* ps:因为这两个数据类型是父类【接口】,所以需要处理一些数据的时候【需要强制类型转换(HttpServletXXXX)】
* @param filterChain
* FilterChain数类型【接口类型】 翻译过来是 过滤链
* 作用:在项目中国可能存在多个过滤器,过滤器彼此之间就需要通过过滤器链来完成传递【操作】
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//这里打印一句话,相当于在可客户端访问过来的时候出现的过滤逻辑
System.out.println("过滤之前........doFilter");
//让请求继续向下传递,FilterChain过滤链,如果当前只有一个Filter直接传递下去【Servlet】,若有其他Filter那么就传递到其他的Filter
//无论如何传递,最终都会回到资源中【JSP、Servlet、静态HTML等等】
filterChain.doFilter(servletRequest,servletResponse);
//过滤链发送完毕之后,下面打印语句常出现就相当于对Servlet的过滤处理完毕
System.out.println("过滤之后.......doFilter");
}
@Override
public void destroy() {
System.out.println("过滤器销毁了......");
}
}
步骤3:如果让Filter发挥作用
PS:Filter是不需要手动调用的,Filter是自动触发,触发的原则【就是过滤路径】
路径的配置
注解方式
在自定义Filter类上使用注解@WebFilter(“过滤路径”)
ps:这里参数可以完全参考@WebServlet注解配置,过滤路径是什么就过滤谁
过滤器的过滤路径通常三种形式:
1.精确过滤匹配: 比如: /index.jsp /myservlet1
2.后缀过滤匹配: 比如 *.jsp *.html *.jpg 【千万不要添加(/),即绝对不可以这样配置 / *.jsp】
3.通配符匹配 : 比如 / * 表示拦截过滤所有 ,注意不能使用【/】进行匹配
ps:在匹配时可以增加路径 例如 某个路径下的某个资源 —》 /aaa/bbb/* /aaa/bbb/myservlet 允许
web.xml配置
<!--过滤器XML配置-->
<filter>
<!--名称,多使用类名-->
<filter-name>MyFilter1</filter-name>
<!--类的全限定名称,获取Filter这个类-->
<filter-class>com.qfedu.Filter.MyFilter1</filter-class>
</filter>
<!--映射路径配置-->
<filter-mapping>
<filter-name>MyFilter1</filter-name>
<!--过滤URL的路径【匹配规则参考注解中】-->
<url-pattern>/*</url-pattern>
</filter-mapping>
ps:过滤的过滤路径是可以写多个,在直接中value是一个数组可以使用数组的形式赋值,存在多个过滤路径,在web.xml配置中,可以在filter-mapping标签下的天剑多个url-pattern标签
初级案例(权限验证)
login页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录界面</title>
</head>
<body>
<div>
<form action="/Filter/login" method="post">
<label>账号:</label><input type="text" name ="username"/><br/>
<label>密码:</label><input type="password" name ="password"/><br/>
<input type="submit" value ="登录"/>
</form>
</div>
</body>
</html>
Filter代码
package com.qfedu.Filter.Power;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/*
Filter中使用的注解是 WebFilter
注解中配置的路径是要过滤的路径,不是Filter的路径【即不是Filter类的路径】
/ 表示当前工程的绝对路径 =======》 http://localhost:8080/工程名/admin/xxx.jsp
*/
@WebFilter(filterName = "AdminFilter",value="/admin/*")
public class AdminFilter implements Filter {
public void destroy() {
}
/*
这个才是核心的处理方法
*/
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//filter中如何获获取到数据,可以数据存储在一个作用域中
//将用户的数据存到session中然后进行取出判断 就可以知道用户是否登录了
//建议在使用请求和响应参数的时候 进行强制类型转换方便使用 ---》 HttpServletXXX
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession();
//只要获取到session中存储用户
Object user = session.getAttribute("user");
//如果等于null,说明还还没有登录
if (user == null){
request.getRequestDispatcher("/login.html").forward(req,resp);
return;
}else{
//让程序继续向下访问资源目标
chain.doFilter(req,resp);
}
}
public void init(FilterConfig config) throws ServletException {
}
}
servelt代码
package com.qfedu.Filter.Power;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "LoginServlet",value="/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//登录的核心逻辑
response.setContentType("text/html;charset=UTF-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
if("zhangsan".equalsIgnoreCase(username) && "123456".equals(password)){
request.getSession().setAttribute("user",username);
response.getWriter().println("登录成功!!!");
}else{
request.getRequestDispatcher("/login.html").forward(request,response);
}
}
}
过滤器连
每个过滤器实现某个特定工程,当一个的Filter中的doFilter方法被调用时,Web服务会创建一个代表Filter类中FilterChain传递该方法,在doFilter方法中,开发人员如果调用了FilterChain对象doFilter方法,则Web服务器会检查FilterChain对象总是否还有filter,如果有则地继续调用另外Filter进行处理,如果没有则直接调用目标【资源】
ps:Filter中如何判断是否还有其他Filter对象进行过滤,这个原则就是value路径
演示
package com.qfedu.Filter.FilterChain;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "Filter1",value="/target.jsp")
public class Filter1 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("Filter1 前置代码1");
chain.doFilter(req, resp);
System.out.println("Filter1 前置代码2");
}
public void init(FilterConfig config) throws ServletException {
}
}
package com.qfedu.Filter.FilterChain;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "Filter2",value="/target.jsp")
public class Filter2 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("Filter2 前置代码1");
chain.doFilter(req, resp);
System.out.println("Filter2 前置代码2");
}
public void init(FilterConfig config) throws ServletException {
}
}
多个Filter过滤器特点展示
所有的filter和相同资源默认都执行在同一个线程中
package com.qfedu.Filter.FilterChain;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "Filter1",value="/target.jsp")
public class Filter1 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("Filter1 前置代码1");
System.out.println("Filter1中的线程:"+Thread.currentThread().getName());
chain.doFilter(req, resp);
System.out.println("Filter1中的线程:"+Thread.currentThread().getName());
System.out.println("Filter1 前置代码2");
}
public void init(FilterConfig config) throws ServletException {
}
}
package com.qfedu.Filter.FilterChain;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "Filter2",value="/target.jsp")
public class Filter2 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("Filter2 前置代码1");
System.out.println("Filter2中的线程:"+Thread.currentThread().getName());
chain.doFilter(req, resp);
System.out.println("Filter2中的线程:"+Thread.currentThread().getName());
System.out.println("Filter2 前置代码2");
}
public void init(FilterConfig config) throws ServletException {
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
System.out.println("target.jsp页面被执行了");
System.out.println("JSP页面线程:"+Thread.currentThread().getName());
%>
</body>
</html>
多个Filter共同执行的时候,他们都使用同一个【request】对象
package com.qfedu.Filter.FilterChain;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "Filter1",value="/target.jsp")
public class Filter1 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("Filter1 前置代码1");
System.out.println("第一个Filter1在这个类中进行值的设置");
req.setAttribute("key1","value1");
chain.doFilter(req, resp);
System.out.println("Filter1 前置代码2");
}
public void init(FilterConfig config) throws ServletException {
}
}
package com.qfedu.Filter.FilterChain;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "Filter2",value="/target.jsp")
public class Filter2 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("Filter2 前置代码1");
//获取存在request中的值;
System.out.println("Filter2中获取request中存储的值:"+req.getAttribute("key1"));
chain.doFilter(req, resp);
System.out.println("Filter2 前置代码2");
}
public void init(FilterConfig config) throws ServletException {
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
System.out.println("target.jsp页面被执行了");
System.out.println("JSP页面线程:"+Thread.currentThread().getName());
System.out.println("JSP页面中获取Filter1中存储属性值:"+request.getAttribute("key1"));
%>
</body>
</html>
FilterConfig类过滤器初始化参数(了解)
FilterConfig它就是Filter类的配置类,Tomcat每次创建Filter的时候,也会同时创建一个FilterConfig类,这个类包含了Filter配置文件的配置信息,FilterConfig可以获取Filter中的一些配置内容:【Filter的配置名称 , Filter的初始化参数, 获取ServletContext对象】
package com.qfedu.Filter.FilterConfig;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
@WebFilter(filterName = "FilterConfig",value="/*",initParams = {@WebInitParam(name="username",value="123456")})
public class FilterConfigDemo implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
chain.doFilter(req, resp);
}
public void init(javax.servlet.FilterConfig config) throws ServletException {
System.out.println("获取去Filter名称"+config.getFilterName());
System.out.println("获取Filter中初始化参数:"+config.getInitParameter("username"));
System.out.println("获取ServletContext对象:"+config.getServletContext());
}
}
Filter过滤案例
案例1:过滤脏词
package com.qfedu.Filter.Filterdirty;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebFilter(filterName = "DortyFilter",value = "/dirty")
public class DirtyFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//可以在这里获取参数值,并对参数值进行判断,并修改为符合词
chain.doFilter(new Dirty((HttpServletRequest)req), resp);
}
/*
在doFilter方法中ServletRequest接口,有很多无用方法,所以我们可以针对火球参数的方进行一个修改直接对
属性值进行一个处理
因为ServletRequest接口如果实现,方法太多,所以可以选着它的一个子类实现HttpServletRequestWrapper
*/
static class Dirty extends HttpServletRequestWrapper{
List<String> list = new ArrayList<>();
public Dirty(HttpServletRequest request){
super(request);
//构建的同时将脏词存进来
list.add("SB");
list.add("MD");
list.add("王八蛋");
list.add("mmp");
list.add("二狗子");
}
//重写方法
@Override
public String getParameter(String name) {
//根据表单中内容,获取数据并进行修改
String parameter = super.getParameter(name);
for(String str : list){
if(parameter.equalsIgnoreCase(str)){
parameter = "世界太美好了";
}
}
return parameter;
}
}
public void init(FilterConfig config) throws ServletException {
}
}
package com.qfedu.Filter.Filterdirty;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "DirtyServlet",value="/dirty")
public class DirtyServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//有了过滤器之后,可以将Servlet中的参数进行存储,并交给Filter来处理
String username = request.getParameter("username");
String password = request.getParameter("password");
String lovename = request.getParameter("lovename");
System.out.println("获取的数据为:"+username+"\n"+password+"\n"+lovename);
}
}
案例2:过滤器解决编码问题
package com.qfedu.Filter.Filterdirty;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
//编码解决
@WebFilter(filterName = "EncodingFilter",value ="/*")
public class EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//提供统一的请求和响应的乱码处理
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
}
总结
如果是使用Filter过滤Servlet,在执行Servlet之前客户端会先把请求发送给Filter,处理完成之后在到达Servlet,响应时,会根据执行流程再次反向执行Filter
Filter可以解决多个Servlet中共性代码冗余问题(例如:乱码问题,异常问题,登录验证等等)
所有Filter和目标资源默认都执行在同一个线程中,多个Filter共同执行的时候,他们都是用同一个request对象