前言

  前面其实已经把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. iOS 微信支付流程详解

    背景 自微信支付.支付宝支付入世以来,移动端的支付日渐火热.虚拟货币有取代实体货币的趋向(这句纯属扯淡,不用管),支付在app开发中是一项基本的功能,有必要去掌握.从难易程度上讲,不管是微信支付还是支 ...

  2. jmeter系列-------脚本调试

    1.调试的时候 可以只跑需要调试的接口,禁用其他的接口 2.每个接口都需要增加断言眼,保证脚本的结果的正确性 3.验证脚本的可靠性,可以切换用户(测试变量)来进行调试 4.使用Debug Sample ...

  3. import和require

    es6 的 import 语法跟 require 不同,而且 import 必须放在文件的最开始,且前面不允许有其他逻辑代码,这和其他所有编程语言风格一致. import不同与require,它是编译 ...

  4. Cassandra HBase和MongoDb性能比较

    详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp68这是一篇基于亚马逊云平台上对三个主流的NoSQL数据库性能比较,在读写 ...

  5. Maven(二)Maven项目的创建(命令、myeclipse)及生命周期

    上一篇给大家介绍了Maven的概念和仓库的一些信息,接下来给大家分享一下使用命令和MyEclipse创建Maven项目 一.使用命令管理Maven项目 1.1.创建Maven java项目 1)创建一 ...

  6. CCNA+NP学习笔记—交换网络篇

    本章关于企业网络的最底层--交换层,难度较低,主要为以后三层的路由做铺垫.所有笔记的分类顺序为:序章→交换层→路由层→运营商,体现了从企业网到互联网的学习顺序. 注:思科设备命令行通常不分大小写!以后 ...

  7. 【Alpha】——Fourth Scrum Meeting

    一.今日站立式会议照片 二.每个人的工作 成员 昨天已完成的工作 今天计划完成的工作 李永豪 完善添加功能 测试统计功能 郑靖涛 完善删除功能 着手编写报表设计 杨海亮 完善查找功能 协助编写统计功能 ...

  8. 201521123090 《Java程序设计》 第8周学习总结

    本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 书面作业 本次作业题集集合 List中指定元素的删除(题目4-1) 1.1 ...

  9. 201521123053《Java设计与程序》第六周学习总结

    ---恢复内容结束--- 1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结.   注1:关键词与内容不求多,但 ...

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

    1. 本章学习总结 2. 书面作业 Q1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试改正该错误.并分析输出结果. 1. ...