前言

  前面其实已经把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返回的post data乱码

    通过csv 跑出来的结果 解决方法: 在CSV Data Set Config中将File Encoding设置为GB2312将Allow quoted data 设置为true  

  2. 搞java的都土鳖

    spring不就几个破框架让人们下载使用吗,但是官网什么都有,就是没有下载链接.java程序员被那些垃圾框架强奸的体无完肤,还乐在其中,还什么SSH,哇哦!java好像跟企业干上了,什么企业bean, ...

  3. C#将Excel数据表导入SQL数据库的两种方法(转)

    最近用写个winform程序想用excel 文件导入数据库中,网上寻求办法,找到了这个经过尝试可以使用. 方法一: 实现在c#中可高效的将excel数据导入到sqlserver数据库中,很多人通过循环 ...

  4. 第1阶段——u-boot分析之make指令(2)

    通过make 100ask24x0_config 指令配置好芯片选型后,使用make指令来生成uboot.bin文件 本文学习目标: 对Makefile文件进行基本了解,掌握make指令是怎么实现生成 ...

  5. 使用SVG基本操作API

    前面的话 本文将详细介绍SVG基本操作API,并使用这些API操作实例效果 基础API 在javascript中,可以使用一些基本的API来对SVG进行操作 [NS地址] 因为SVG定义在其自身的命令 ...

  6. python-分页代码

    page.py ''' django内使用方式: all_count = models.UserInfo.objects.all().count() # path_info 当前页的url # all ...

  7. 九度OJ 1011 最长子串

    #include <iostream> #include <string> #include <sstream> #include <math.h> u ...

  8. JAVA基础第二组(5道题)

    6.[程序6] 题目:输入两个正整数m和n,求其最大公约数和最小公倍数.        1.程序分析:利用辗除法. package com.niit.homework1; import java.ut ...

  9. 201521123045 《Java程序设计》第7周学习总结

    Java 第七周总结 1. 本周学习总结 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 public boolean contains(Obj ...

  10. 201521123042 《Java程序设计》 第10周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 上周总结了异常,这周主要总结多线程. 2. 书面作业 本次PTA作业题集异常.多线程 1.finally 题 ...