前言

  前面其实已经把Servlet中所有的内容都介绍完了,这篇讲补充一点乱码和重定向与转发之间的区别!

一、request请求参数出现乱码问题

1.1、get请求

  1)乱码示例

  get请求的参数是在url后面提交过来的,也就是在请求行中。

  

  

  结果:

    

    Servlet_demo_0040是一个普通的Servlet,浏览器访问它时,使用get请求方式提交了一个username=小明的参数值,在doGet中获取该参数值,并且打印到控制台,发现出现乱码

  2)出现乱码原因

    前期知识:

      码表:是一种规则,用来让我们看得懂的语言转换为电脑能够认识的语言的一种规则,有很多中码表,IS0-8859-1,GBK,UTF-8,UTF-16等一系列码表,

         比如GBK,UTF-8,UTF-16都可以标识一个汉字,而如果要标识英文,就可以用IS0-8859-1等别的码表。

      编码:将我们看得懂的语言转换为电脑能够认识的语言。这个过程就是编码的作用。

      解码:将电脑认识的语言转换为我们能看得懂得语言。这个过程就是解码的作用

    这里只能够代表经过一次编码例子,有些程序中,会将一个汉字或者一个字母用不同的码表连续编码几次,那么第一次编码还是上面所说的作用,第二次编码的话,

    就是将电脑能够认识的语言转换为电脑能够认识的语言(转换规则不同),那么该解码过程,就必须要经过两次解码,也就是编码的逆过程,下面这个例子就很好的说明了这个问题:

    浏览器使用的是UTF-8码表,通过http协议传输,http协议只支持IS0-8859-1,到了服务器,默认也是使用的是IS0-8859-1的码表,看图:

    

    从上面的图中可以看出,就是三个过程,经历了两次编码,所以就需要进行两次解码:

      1)浏览器将"小明"使用UTF-8码表进行编码(因为小明这个是汉字,所以使用能标识中文的码表,这也是我们可以在浏览器上可以手动设置的,如果使用了不能标识中文的码表,那么就将会出现乱码,

        因为码表中找不到中文对应的计算机符号,就可能会用??等其他符号表示),编码后得到的为 1234 ,将其通过http协议传输。

      2)在http协议传输,只能用ISO-8859-1码表中所代表的符号,所以会将我们原先的1234再次进行一次编码,这次使用的是ISO-8859-1,得到的为 ???? ,然后传输到服务器。

      3)服务器获取到该数据是经过了两次编码后得到的数据,所以必须跟原先编码的过程逆过来解码,先是UTF-8编码,然后在ISO-8859-1编码,那么解码的过程,就必须是先ISO-8859-1解码,然后在用UTF-8解码,

        这样就能够得到正确的数据。????.getBytes("ISO-8859-1");//第一次解码,转换为电脑能够识别的语言, new String(1234,"UTF-8");//第二次解码,转换为我们认识的语言

  3)解决方法

    

    结果:

      

1.2、post请求

  post请求方式的参数是在请求体中,相对于get请求简单很多,没有经过http协议这一步的编码过程,所以只需要在服务器端,设置服务器解码的码表跟浏览器编码的码表是一样的就行了,

  在这里浏览器使用的是UTF-8码表编码,那么服务器端就设置解码所用码表也为UTF-8就OK了。

  设置服务器端使用UTF-8码表解码:

    request.setCharacterEncoding("UTF-8");  //命令Tomcat使用UTF-8码表解码,而不用默认的ISO-8859-1了。

  所以在很多时候,在doPost方法的第一句,就是这句代码,防止获取请求参数时乱码。

总结请求参数乱码问题:

  get请求和post请求方式的中文乱码问题处理方式不同

  get:请求参数在请求行中,涉及了http协议,手动解决乱码问题,知道出现乱码的根本原因,对症下药,其原理就是进行两次编码,两次解码的过程

    new String(xxx.getBytes("ISO-8859-1"),"UTF-8");

  post:请求参数在请求体中,使用servlet API解决乱码问题,其原理就是一次编码一次解码,命令tomcat使用特定的码表解码。

    request.setCharaterEncoding("UTF-8");

二、response响应回浏览器出现中文乱码

  首先介绍一下,response对象是如何向浏览器发送数据的。两种方法,一种getOutputStream,一种getWrite:  

    ServletOutputStream getOutputStream();  //获取输出字节流,提供write() 和 print() 两个输出方法。

    PrintWriter getWrite();  //获取输出字符流,提供write() 和 print()两个输出方法。

  print()方法底层都是使用write()方法的,相当于print()方法就是将write()方法进行了封装,使开发者更方便快捷的使用,想输出什么,就直接选择合适的print()方法,而不用考虑如何转换字节。  

2.1、ServeltOutputStream getOutputStream(); 

   

  结果:不能直接输出中文,直接输出中文会报异常    

    

  报异常的源码分析:

    

  解决方法:

    resp.getoutputStream().write("哈哈哈,我要输出到浏览器".getBytes("UTF-8"));

    将要输出的汉字先用UTF-8进行编码,而不用让tomcat来进行编码,这样如果浏览器用的是UTF-8码表进行解码的话,那么就会正确输出,如果浏览器用的不是UTF-8,那么还是会出现乱码,

    所以说这个关键要看浏览器用的什么码表,这个就不太好,这里还要注意一点,就是使用的是write(byte)方法,因为print()方法没有输出byte类型的方法。

    测试:因为我用的是谷歌浏览器它默认使用的是GB2312所以这里使用的是GB2312

      

      

2.2、PrintWriter getWrite();

  直接输出中文,不会报异常,但是肯定会报异常,因为用ISO-8859-1的码表不能标识中文,一开始就是错的,怎么解码编码读没用了。

  有三种方法来让其正确输出中文:

  1)使用Servlet API  response.setCharacterEncoding()

    response.setCharacterEncoding("UTF-8");  //让tomcat将我们要响应到浏览器的中文用UTF-8进行编码,而不使用默认的ISO-8859-1了,这个还是要取决于浏览器是不是用的UTF-8的码表,跟上面的一样有缺陷。

    测试:因为我用的是谷歌浏览器它默认使用的是GB2312所以这里使用的是GB2312

     

  2)通知tomcat和浏览器都使用同一张码表

    response.setHeader("content-type","text/html;charset=uft-8");  //手动设置响应内容,通知tomcat和浏览器使用utf-8来进行编码和解码。  

      charset=uft-8就相当于response.setCharacterEncoding("UTF-8");//通知tomcat使用utf-8进行编码

      response.setHeader("content-type","text/html;charset=uft-8");//合起来,就是既通知tomcat用utf-8编码,又通知浏览器用UTF-8进行解码。

    response.setContentType("text/html;charset=uft-8");  //使用Servlet API 来通知tomcat和强制浏览器使用UTF-8来进行编码解码,这个的底层代码就是上一行的代码,进行了简单的封装而己。

      

  3)通知tomcat,在使用html<meta>通知浏览器 (html源码),注意:<meta>建议浏览器应该使用编码,不能强制要求

    

    所以response在响应时,只要通知tomcat和浏览器使用同一张码表,一般使用第二种方法,那么就可以解决响应的乱码问题了

三、总结请求和响应的乱码

3.1、请求乱码 

  get请求:

    经过了两次编码,所以就要两次解码

      第一次解码:xxx.getBytes("ISO-8859-1");得到yyy

      第二次解码:new String(yyy,"utf-8");

    连续写:new String(xxx.getBytes("ISO-8859-1"),"UTF-8");

  post请求:

    只经过一次编码,所以也就只要一次解码,使用Servlet API request.setCharacterEncoding();

    request.setCharacterEncoding("UTF-8");  //不一定解决,取决于浏览器是用什么码表来编码,浏览器用UTF-8,那么这里就写UTF-8。

3.2、响应乱码

  getOutputStream();:

    使用该字节输出流,不能直接输出中文,会出异常,要想输出中文,解决方法如下

    解决:getOutputStream().write(xxx.getBytes("UTF-8"));  //手动将中文用UTF-8码表编码,变成字节传输,变成字节后,就不会报异常,并且tomcat也不会在编码,因为已经编码过了,所以到浏览器后,

                                如果浏览器使用的是UTF-8码表解码,那么就不会出现中文乱码,反之则出现中文乱码,所以这个方法,不能完全保证中文不乱码

  getWrite();:

    使用字符输出流,能直接输出中文,不会出异常,但是会出现乱码。能用三种方法解决,一直使用第二种方法

    解决:通知tomcat和浏览器使用同一张码表。

    response.setContentType("text/html;charset=utf-8");  //通知浏览器使用UTF-8解码

    通知tomcat和浏览器使用UTF-8编码和解码。这个方法的底层原理是这句话:response.setHeader("contentType","text/html;charset=utf-8");

  注意:getOutputStream()和getWrite() 这两个方法不能够同时使用,一次只能使用一个,否则报异常     

四、Servlet中请求和转发的区别

4.1、使用方式 

  1)在servlet中调用转发、重定向的语句如下:

request.getRequestDispatcher("new.jsp").forward(request, response); //转发到new.jsp
response.sendRedirect("new.jsp"); //重定向到new.jsp

  2)在jsp页面中你也会看到通过下面的方式实现转发:

<jsp:forward page="apage.jsp" />

  当然也可以在jsp页面中实现重定向:

<%response.sendRedirect("new.jsp"); %> //重定向到new.jsp

  示例:

//获取username信息
String username=request.getParameter("username");
//转发与重定向
if(username.equals("admin")){
//提示用户已存在,不能注册
request.setAttribute("message","该用户已存在,不能注册");//添加提示信息,需要在userCreate.jsp页面中进行提示信息展示
request.getRequestDispatcher("userCreate.jsp").forward(request, response);//转法
}else{
//提示注册成功
request.setAttribute("message","注册成功");
response.sendRedirect("indext.jsp");//重定向
}

4.2、区别:重定向和转发的工作流程

  

  1)转发的工作流程‘

    第一步:客户浏览器发送http请求
    第二步:web服务器接受此请求    
    第三步:调用内部的一个方法在容器内部完成请求处理和转发动作  
    第四步:将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,
        也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。 

  2)重定向的工作流程

    

    第一步:客户浏览器发送http请求
    第二步:web服务器接受后发送302状态码响应及对应新的location给客户浏览器
    第三步:客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址
    第四步:服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。
        在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。

  总结:一句话,转发是服务器行为,重定向是客户端行为。

4.3、区别:请求次数

  1)重定向

    重定向,其实是两次request

    第一次,客户端request   A,服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。

    举例:          

    response.sendRedirect("loginsuccess.jsp"); 

  2)转发

    转发是一次request  

    请求转发是服务器内部把对一个request/response的处理权,移交给另外一个

    对于客户端而言,它只知道自己最早请求的那个A,而不知道中间的B,甚至C、D。传输的信息不会丢失。  

     RequestDispatcher dis=request.getRequestDispatcher(“loginsuccess.jsp”);
dis.forward(request,response);

4.4、生活中的例子说明区别

  

  假设你去办理某个执照
  重定向:你先去了A局,A局的人说:“这个事情不归我们管,去B局”,然后,你就从A退了出来,自己乘车去了B局。
  转发:你先去了A局,A局看了以后,知道这个事情其实应该B局来管,但是他没有把你退回来,而是让你坐一会儿,自己到后面办公室联系了B的人,让他们办好后,送了过来。

五、总结Servlet中请求和转发的区别

  1)重定向的执行过程:Web服务器向浏览器发送一个http响应--》浏览器接受此响应后再发送一个新的http请求到服务器--》服务器根据此请求寻找资源并发送给浏览器。它可以重定向到任意URL,不能共享request范围内的数据。
  2)重定向是在客户端发挥作用,通过新的地址实现页面转向。
  3)重定向是通过浏览器重新请求地址,在地址栏中可以显示转向后的地址。
  4)转发过程:Web服务器调用内部方法在容器内部完成请求和转发动作--》将目标资源发送给浏览器,它只能在同一个Web应用中使用,可以共享request范围内的数据。
  5)转发是在服务器端发挥作用,通过forward()方法将提交信息在多个页面间进行传递。
  6)转发是在服务器内部控制权的转移,客户端浏览器的地址栏不会显示出转向后的地址。

喜欢就点个“推荐”哦!

JavaWeb(一)Servlet中乱码解决与转发和重定向的区别的更多相关文章

  1. javaweb之Servlet,http协议以及请求转发和重定向

    本文是作者原创,版权归作者所有.若要转载,请注明出处. 一直用的框架开发,快连Servlet都忘了,此文旨在帮自己和大家回忆一下Servlet主要知识点.话不多说开始吧 用idea构建Servlet项 ...

  2. Servlet中转发和重定向的区别

    Servlet中页面的跳转有两种方式:转发和重定向. 1.转发和重定向的区别 ①转发是服务器行为,重定向是客户端行为. ②转发是浏览器发生了一次请求,重定向至少是两次请求. ③转发地址栏中的url不会 ...

  3. SERVLET API中转发与重定向的区别?

    SERVLET API中转发与重定向的区别? 1.转发(forward方法) 转发仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址. 转发是服务器请求资源,服务器直接访问目标地址的 ...

  4. servlet之转发与重定向的区别

    转发(服务器端跳转):  一次请求 <jsp:forward> request.getRequestDispatcher("new.jsp").forward(requ ...

  5. Java中转发与重定向的区别

        转发与重定向的区别 转发是服务器行为,重定向是客户端行为 1.转发在服务器端完成的:重定向是在客户端完成的2.转发的速度快:重定向速度慢3.转发的是同一次请求:重定向是两次不同请求4.转发不会 ...

  6. Java 请求转发和重定向的区别以及JavaWeb三大作用域

    三大作用域以及转发和重定向 学习总结 1. 转发和重定向 转发 重定向 转发和重定向的区别: 什么时候用转发什么时候用重定向 三大作用域 作用域类型 作用域方法 如何选择作用域 总结 学习总结 1. ...

  7. jsp内置对象 转发与重定向的区别

    jsp 内置对象  转发与重定向的比较 重定向和转发有一个重要的不同:当使用转发时,JSP容器将使用一个内部的方法来调用目标页面,新的页面继续处理同一个请求,而浏览器将不会知道这个过程. 与之相反,重 ...

  8. Java/Java Web中乱码解决汇总

    在开发Java/Java Web Application过程中,往往会出现乱码问题,而且有的时候真会弄得人很烦,浪费太多的时间. 记得之前看过一篇帖子,详细解释了Encoding/Decoding过程 ...

  9. JavaWeb(一)-Servlet中的Config和Context

    一.ServletConfig对象 1.1获取一个servletConfig对象 1)通过初始化方法获得一个servletconfig 2)通过继承父类(GenericServlet.)得到一个ser ...

随机推荐

  1. jmeter后置处理器 JSON Extractor取多个变量值

    1.需要获取响应数据的请求右键添加-后置处理器-JSON Extractor 2.如果要获取json响应数据多个值时,设置的Variable names (后续引用变量值的变量名设置)与JSON Pa ...

  2. Android studio 安装的安装一些问题

    在国内如何更新android sdk? 由于众所周知的某些原因,我们无法直接连接android sdk的更新服务更新sdk,所以可以通过国内的ftp站点把常用的sdk组件如android platfo ...

  3. leetcode 001 Two Sun

    Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...

  4. C# .NET Socket 简单实用框架

    背景: 首先向各位前辈,大哥哥小姐姐问一声好~ 这是我第一次写博客,目前为一个即将步入大四的学生,上学期在一家公司实习了半年,后期发现没有动力,而且由于薪水问题(废话嘛),于是跳槽到这家新的公司. 说 ...

  5. Java jdk 快速配置

    JAVA_HOME C:\Program Files\Java\jdk1.8.0_92   Path %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;   CLASSPATH ...

  6. linux环境下安装nginx步骤

    开始前,请确认gcc g++开发类库是否装好,默认已经安装. ububtu平台编译环境可以使用以下指令 apt-get install build-essential apt-get install ...

  7. js函数防抖、节流实现

    防抖 Debounce 函数防抖就是,延迟一段时间再执行函数,如果这段时间内又触发了该函数,则延迟重新计算: // 简单实现 function debounce(fn, wait) { let t r ...

  8. quartz源码分析——执行引擎和线程模型

    title: quartz源码分析--执行引擎和线程模型 date: 2017-09-09 23:14:48 categories: quartz tags: [quartz, 源码分析] --- - ...

  9. 自己编写服务启动脚本(一):functions文件详细分析和说明

    本文目录: 1.几个显示函数2.action函数3.is_true和is_false函数4.confirm函数5.pid检测相关函数 5.1 checkpid.__pids_var_run和__pid ...

  10. 命令行利用KVM创建虚拟机

    一,实验环境 OS:CENTOS6.5 X86_64 二,KVM宿主环境配置 1.cat /proc/cpuinfo | egrep 'vmx|svm'  //查看是否支持虚拟技术 2.安装KVM相关 ...