首页 > 编程语言 >javaWeb中的编码解码

javaWeb中的编码解码

时间:2023-05-29 13:04:37浏览次数:48  
标签:编码 浏览器 javaWeb URL 解码 表单 cc


在上篇博客中LZ介绍了前面两种场景(IO、内存)中的Java编码解码操作,其实在这两种场景中我们只需要在编码解码过程中设置正确的编码解码方式一般而言是不会出现乱码的。对于我们从事java开发的人而言,其实最容易也是产生乱码最多的地方就是web部分。首先我们来看在javaWeb中有哪些地方存在编码转换操作。

编码&解码

通过下图我们可以了解在javaWeb中有哪些地方有转码:

javaWeb中的编码解码_数据库

用户想服务器发送一个HTTP请求,需要编码的地方有url、cookie、parameter,经过编码后服务器接受HTTP请求,解析HTTP请求,然后对url、cookie、parameter进行解码。在服务器进行业务逻辑处理过程中可能需要读取数据库、本地文件或者网络中的其他文件等等,这些过程都需要进行编码解码。当处理完成后,服务器将数据进行编码后发送给客户端,浏览器经过解码后显示给用户。在这个整个过程中涉及的编码解码的地方较多,其中最容易出现乱码的位置就在于服务器与客户端进行交互的过程。

上面整个过程可以概括成这样,页面编码数据传递给服务器,服务器对获得的数据进行解码操作,经过一番业务逻辑处理后将最终结果编码处理后传递给客户端,客户端解码展示给用户。所以下面我就请求对javaweb的编码&解码进行阐述。

请求

客户端想服务器发送请求无非就通过四中情况:

1、URL方式直接访问。

2、页面链接。

3、表单get提交

4、表单post提交

URL方式

对于URL,如果该URL中全部都是英文的那倒是没有什么问题,如果有中文就要涉及到编码了。如何编码?根据什么规则来编码?又如何来解码呢?下面LZ将一一解答!首先看URL的组成部分:

javaWeb中的编码解码_表单_02

在这URL中浏览器将会对path和parameter进行编码操作。为了更好地解释编码过程,使用如下URL

http://127.0.0.1:8080/perbank/我是cm?name=我是cm

将以上地址输入到浏览器URL输入框中,通过查看http 报文头信息我们可以看到浏览器是如何进行编码的。下面是IE、Firefox、Chrome三个浏览器的编码情况:

javaWeb中的编码解码_服务器_03

javaWeb中的编码解码_数据库_04

javaWeb中的编码解码_服务器_05

可以看到各大浏览器对“我是”的编码情况如下:



 

path部分

Query String

Firefox

E6 88 91 E6 98 AF

E6 88 91 E6 98 AF

Chrome

E6 88 91 E6 98 AF

E6 88 91 E6 98 AF

IE

E6 88 91 E6 98 AF

CE D2 CA C7



查阅上篇博客的编码可知对于path部分Firefox、chrome、IE都是采用UTF-8编码格式,对于Query String部分Firefox、chrome采用UTF-8,IE采用GBK。至于为什么会加上%,这是因为URL的编码规范规定浏览器将ASCII字符非 ASCII 字符按照某种编码格式编码成 16 进制数字然后将每个 16 进制表示的字节前加上“%”。

当然对于不同的浏览器,相同浏览器不同版本,不同的操作系统等环境都会导致编码结果不同,上表某一种情况,对于URL编码规则下任何结论都是过早的。由于各大浏览器、各个操作系统对URL的URI、QueryString编码都可能存在不同,这样对服务器的解码势必会造成很大的困扰,下面我们将已tomcat,看tomcat是如何对URL进行解码操作的。

解析请求的 URL 是在 org.apache.coyote.HTTP11.InternalInputBuffer 的 parseRequestLine 方法中,这个方法把传过来的 URL 的 byte[] 设置到 org.apache.coyote.Request 的相应的属性中。这里的 URL 仍然是 byte 格式,转成 char 是在 org.apache.catalina.connector.CoyoteAdapter 的 convertURI 方法中完成的


1. protected void convertURI(MessageBytes uri, Request request)   
2. throws Exception {   
3.                     ByteChunk bc = uri.getByteChunk();   
4. int length = bc.getLength();   
5.                     CharChunk cc = uri.getCharChunk();   
6. 1);   
7. //获取URI解码集  
8. if (enc != null) {   
9.                         B2CConverter conv = request.getURIConverter();   
10. try {   
11. if (conv == null) {   
12. new B2CConverter(enc);   
13.                                 request.setURIConverter(conv);   
14.                             }   
15. catch (IOException e) {...}   
16. if (conv != null) {   
17. try {   
18.                                 conv.convert(bc, cc, cc.getBuffer().length - cc.getEnd());   
19.                                 uri.setChars(cc.getBuffer(), cc.getStart(), cc.getLength());   
20. return;   
21. catch (IOException e) {...}   
22.                         }   
23.                     }   
24. // Default encoding: fast conversion   
25. byte[] bbuf = bc.getBuffer();   
26. char[] cbuf = cc.getBuffer();   
27. int start = bc.getStart();   
28. for (int i = 0; i < length; i++) {   
29. char) (bbuf[i + start] & 0xff);   
30.                     }   
31. 0, length);   
32.     }


 

从上面的代码可知,对URI的解码操作是首先获取Connector的解码集,该配置在server.xml中



1. <Connector URIEncoding="utf-8"  />



 

如果没有定义则会采用默认编码ISO-8859-1来解析。

对于Query String部分,我们知道无论我们是通过get方式还是POST方式提交,所有的参数都是保存在Parameters,然后我们通过request.getParameter,解码工作就是在第一次调用getParameter方法时进行的。在getParameter方法内部它调用org.apache.catalina.connector.Request 的 parseParameters 方法,这个方法将会对传递的参数进行解码。下面代码只是parseParameters方法的一部分:



1. //获取编码  
2.    String enc = getCharacterEncoding();  
3. //获取ContentType 中定义的 Charset  
4. boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();  
5. if (enc != null) {    //如果设置编码不为空,则设置编码为enc  
6.       parameters.setEncoding(enc);  
7. if (useBodyEncodingForURI) {   //如果设置了Chartset,则设置queryString的解码为ChartSet  
8.           parameters.setQueryStringEncoding(enc);      
9.       }  
10. else {     //设置默认解码方式  
11.       parameters.setEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);  
12. if (useBodyEncodingForURI) {  
13.           parameters.setQueryStringEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);  
14.       }  
15.   }


 

从上面代码可以看出对query String的解码格式要么采用设置的ChartSet要么采用默认的解码格式ISO-8859-1。注意这个设置的ChartSet是在 http Header中定义的ContentType,同时如果我们需要改指定属性生效,还需要进行如下配置:



 

1. <Connector URIEncoding="UTF-8" useBodyEncodingForURI="true"/>



 

上面部分详细介绍了URL方式请求的编码解码过程。其实对于我们而言,我们更多的方式是通过表单的形式来提交。

表单GET

我们知道通过URL方式提交数据是很容易产生乱码问题的,所以我们更加倾向于通过表单形式。当用户点击submit提交表单时,浏览器会更加设定的编码来编码数据传递给服务器。通过GET方式提交的数据都是拼接在URL后面(可以当做query String??)来提交的,所以tomcat服务器在进行解码过程中URIEncoding就起到作用了。tomcat服务器会根据设置的URIEncoding来进行解码,如果没有设置则会使用默认的ISO-8859-1来解码。假如我们在页面将编码设置为UTF-8,而URIEncoding设置的不是或者没有设置,那么服务器进行解码时就会产生乱码。这个时候我们一般可以通过new String(request.getParameter("name").getBytes("iso-8859-1"),"utf-8") 的形式来获取正确数据。

表单POST

对于POST方式,它采用的编码也是由页面来决定的即contentType。当我通过点击页面的submit按钮来提交表单时,浏览器首先会根据ontentType的charset编码格式来对POST表单的参数进行编码然后提交给服务器,在服务器端同样也是用contentType中设置的字符集来进行解码(这里与get方式就不同了),这就是通过POST表单提交的参数一般而言都不会出现乱码问题。当然这个字符集编码我们是可以自己设定的:request.setCharacterEncoding(charset) 。


标签:编码,浏览器,javaWeb,URL,解码,表单,cc
From: https://blog.51cto.com/u_16131764/6370104

相关文章

  • java是如何编码解码的
    编码&解码在java中主要有四个场景需要进行编码解码操作:1:I/O操作2:内存3:数据库4:javaWeb下面主要介绍前面两种场景,数据库部分只要设置正确编码格式就不会有什么问题,javaWeb场景过多需要了解URL、get、POST的编码,servlet的解码,所以javaWeb场景下节LZ介绍。I/O操作在前面LZ就提过乱码问......
  • php半角符号编码
    在PHP中,半角符号的编码方式与全角符号不同。以下是一些常见半角符号的编码示例:空格: &#32; 或者 &nbsp;句号: &#46;冒号: &#58;分号: &#59;左括号: &#40;右括号: &#41;引号: &#34;示例代码如下:<?phpecho"空格:"."&nbsp;"."&#32;"."&......
  • Python 标准类库-因特网数据处理之Base64数据编码
    该模块提供将二进制数据编码为可打印ASCII字符并将这种编码解码回二进制数据的功能。它为RFC3548中指定的编码提供编码和解码功能。定义了Base16、Base32和Base64算法,以及事实上的标准Ascii85和Base85编码。RFC3548编码适用于对二进制数据进行编码,以便可以安全地通过电子邮件......
  • 维吉尼亚密码编码实验
    【实验目的】熟练掌握多表古典密码维吉尼亚密码加密解密算法原理及实现和应用。【知识点】维吉尼亚密码【实验原理】维吉尼亚密码(Vigenèrecipher)是由法国科学家BlaisedeVigenère于1858年提出的一种代换密码,它是多表代换密码的典型代表。维吉尼亚密码引入了“密钥”的概念......
  • 仿射密码编码实验
    【实验目的】熟练掌握多表古典密码仿射密码加密和解密算法原理及实现和应用。【知识点】仿射密码【实验原理】单码加密法的另一种形式称为仿射加密法(affinecipher)。在仿射加密法中,字母表的字母被赋予一个数字,例如a=0,b=1,c=2...z=25。仿射加密法的密钥为0-25之间的数字对。仿射......
  • 乘法密码编码实验
    【实验目的】熟练掌握多表古典密码简单乘法加密算法原理及实现和应用。【知识点】乘法密码编码【实验原理】1.乘法密码原理乘法密码是简单代替密码的一种。需要预先知道消息元素的个数,加密的过程其实是相当于对明文消息所组成的数组下标进行加密,然后用明文消息中加密后位置......
  • 信源编码的代码实现 (香农编码、费诺编码、哈夫曼编码、游程编码、算术编码)
    @[TOC](文章目录)香农编码(1)将信源消息符号按其出现的概率大小依次排列p1≥p2≥...≥pn(2)确定满足下列不等式的整数码长Ki为-log2(pi)≤Ki<-log2(pi)+1(3)为了编成唯一可译码,计算第i个消息的累加概率(4)将累加概率Pi转换成二进制数。(5)取Pi二进数......
  • drf——全局处理异常、接口文档、jwt介绍、based64编码与解码
    全局异常处理原理#对于前端来讲,后端即便报错,也要返回统一的格式,前端便于处理{code:999,msg:'系统异常,请联系系统管理员'}#只要三大认证,视图类的方法出了异常,都会执行一个函数: rest_framework.viewsimportexception_handler#drf只要出了异常就会执行这是drf的配置文件......
  • drf全局异常处理,接口文档,jwt介绍和原理,base64编码和解码
    drf全局异常处理:只要三大认证,视图类的方法出了异常,都会执行一个函数:rest_framework.viewsimportexception_handlersetting:REST_FRAMEWORK={'EXCEPTION_HANDLER':'app01.exception.commn_exception_handler',#导入自己写的异常类的路径}......
  • 全局异常处理,接口文档,JWT,base64编码解码
    1全局异常处理#对于前端来讲,后端即便报错,也要返回统一的格式,前端便于处理{code:999,msg:'系统异常,请联系系统管理员'}#只要三大认证,视图类的方法出了异常,都会执行一个函数:rest_framework.viewsimportexception_handler###注意:exception_handler#如果异常对象是......