一、问题:

编码问题是JAVA初学者在web开发过程中经常会遇到问题,网上也有大量相关的文章介绍,但其中很多文章并没有对URL中使用了中文等非ASCII的字 符造成服务器后台程序解析出现乱码的问题作出准确的解释和说明。本文将详细介绍由于在URL中使用了中文等非ASCII的字符造成乱码的问题。

1、在URL中中文字符通常出现在以下两个地方:

(1)、Query String中的参数值,比如http://search.china.alibaba.com/search/offer_search.htm?keywords=中国

(2)、servlet path,比如:http://search.china.alibaba.com/selloffer/中国.html

2、出现乱码问题的原因主要是以下几方面:

(1)、浏览器:我们的客户端(浏览器)本身并没有遵循URI编码的规范(http://www.w3.org/International/O-URL-code.html)。

(2)、Servlet服务器:Servlet服务器的没有正确配置。

(3)、开发人员并不了解Servlet的规范和API的含义。

二、基础知识:

1、一个http请求经过的几个环节:

浏览器(ie firefox)【get/post】------------>Servlet服务器------------------------------->浏览器显示

编码                 解码成unicode,然后将显示的内容编码        解码

(1) 浏览器把URL(以及post提交的内容)经过编码后发送给服务器。

(2) 这里的Servlet服务器实际上指的是由Servlet服务器提供的servlet实现ServletRequestWrapper,不同应用服务器的 servlet实现不同,这些servlet的实现把这些内容解码转换为unicode,处理完毕后,然后再把结果(即网页)编码返回给浏览器。

(3) 浏览器按照指定的编码显示该网页。

当对字符串进行编码和解码的时候都涉及到字符集,通常使用的字符集为ISO8859-1、GBK、UTF-8、UNICODE。

2、URL的组成:

域名:端口/contextPath/servletPath/pathInfo?queryString

说明:

1、ContextPath是在Servlet服务器的配置文件中指定的。

对于weblogic:

contextPath是在应用的weblogic.xml中配置。

/

对于tomcat:

contextPath是在server.xml中配置。

对于jboos:

contextPath是在应用的jboss-web.xml中配置。

/

2、ServletPath是在应用的web.xml中配置。

Example

/example/*

2、Servlet API

我们使用以下servlet API获得URL的值及参数。

request.getParameter("name");         // 获得queryString的参数值(来自于get和post),其值经过Servlet服务器URL Decode过的

request.getPathInfo();                // 注意:pathinfo返回的字符串是经过Servlet服务器URL Decode过的。

requestURI = request.getRequestURI(); // 内容为:contextPath/servletPath/pathinfo 浏览器提交过来的原始数据,未被Servlet服务器URL Decode过。

3、开发人员必须清楚的servlet规范:

(1) HttpServletRequest.setCharacterEncoding()方法 仅仅只适用于设置post提交的request body的编码而不是设置get方法提交的queryString的编码。该方法告诉应用服务器应该采用什么编码解析post传过来的内容。很多文章并没 有说明这一点。

(2) HttpServletRequest.getPathInfo()返回的结果是由Servlet服务器解码(decode)过的。

(3) HttpServletRequest.getRequestURI()返回的字符串没有被Servlet服务器decoded过。

(4) POST提交的数据是作为request body的一部分。

(5) 网页的Http头中ContentType("text/html; charset=GBK")的作用:

(a) 告诉浏览器网页中数据是什么编码;

(b) 表单提交时,通常浏览器会根据ContentType指定的charset对表单中的数据编码,然后发送给服务器的。

这里需要注意的是:这里所说的ContentType是指http头的ContentType,而不是在网页中meta中的ContentType。

三、下面我们分别从浏览器和应用服务器来举例说明:

URL:http://localhost:8080/example/中国?name=中国

汉字   编码      二进制表示

中国   UTF-8     0xe4 0xb8 0xad 0xe5 0x9b 0xbd[-28, -72, -83, -27, -101, -67]

中国   GBK       0xd6 0xd0 0xb9 0xfa[-42, -48, -71, -6]

中国   ISO8859-1 0x3f,0x3f[63, 63]信息失去

(一)、浏览器

1、GET方式提交,浏览器会对URL进行URL encode,然后发送给服务器。

(1) 对于中文IE,如果在高级选项中选中总以UTF-8发送(默认方式),则PathInfo是URL Encode是按照UTF-8编码,QueryString是按照GBK编码。

http://localhost:8080/example/中国?name=中国

实际上提交是:

GET /example/%E4%B8%AD%E5%9B%BD?name=%D6%D0%B9%FA

(1) 对于中文IE,如果在高级选项中取消总以UTF-8发送,则PathInfo和QueryString是URL encode按照GBK编码。

实际上提交是:

GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

(3) 对于中文firefox,则pathInfo和queryString都是URL encode按照GBK编码。

实际上提交是:

GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

很显然,不同的浏览器以及同一浏览器的不同设置,会影响最终URL中PathInfo的编码。对于中文的IE和FIREFOX都是采用GBK编码QueryString。

小结:解决方案:

1、URL中如果含有中文等非ASCII字符,则浏览器会对它们进行URLEncode。为了避免浏览器采用了我们不希望的编码,所以最好不要在URL中直接使用非ASCII字符,而采用URL Encode编码过的字符串%.

比如:

URL:http://localhost:8080/example/中国?name=中国

建议:

URL:http://localhost:8080/example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

2、我们建议URL中PathInfo和QueryString采用相同的编码,这样对服务器端处理的时候会更加简单。

2、还有一个问题,我发现很多程序员并不明白URL Encode是需要指定字符集的。不明白的人可以看看这篇文档:http://gceclub.sun.com.cn/Java_Docs/html /zh_CN/api/java/net/URLEncoder.html

2、 POST提交

对于POST方式,表单中的参数值对是通过request body发送给服务器,此时浏览器会根据网页的ContentType("text/html; charset=GBK")中指定的编码进行对表单中的数据进行编码,然后发给服务器。

在服务器端的程序中我们可以通过Request.setCharacterEncoding() 设置编码,然后通过request.getParameter获得正确的数据。

解决方案:

1、从最简单,所需代价最小来看,我们对URL以及网页中的编码使用统一的编码对我们来说是比较合适的。

如果不使用统一编码的话,我们就需要在程序中做一些编码转换的事情。这也是我们为什么看到有网络上大量的资料介绍如何对乱码进行处理,其中很多解决方案都只是一时的权宜之计,没有从根本上解决问题。

(二)、Servlet服务器

Servlet服务器实现的Servlet遇到URL和POST提交的数据中含有%的字符串,它会按照指定的字符集解码。下面两个Servlet方法返回的结果都是经过解码的:

request.getParameter("name");

request.getPathInfo();

这里所说的"指定的字符集"是在应用服务器的配置文件中配置。

(1) tomcat服务器

对于tomcat服务器,该文件是server.xml

maxThreads="150" connectionTimeout="20000"

redirectPort="8443" URIEncoding="GBK"/>

URIEncoding告诉服务器servlet解码URL时采用的编码。

useBodyEncodingForURI告诉服务器解码URL时候需要采用request body指定的编码。

(2) weblogic服务器

对于weblogic服务器,该文件是weblogic.xml

GBK

(三)浏览器显示

浏览器根据http头中的ContentType("text/html; charset=GBK"),指定的字符集来解码服务器发送过来的字节流。我们可以调用 HttpServletResponse.setContentType()设置http头的ContentType。

总结:

1、URL中的PathInfo和QueryString字符串的编码和解码是由浏览器和应用服务器的配置决定的,我们的程序不能设置,不要期望用request.setCharacterEncoding()方法能设置URL中参数值解码时的字符集。

所以我们建议URL中不要使用中文等非ASCII字符,如果含有非ASCII字符的话要使用URLEncode编码一下,比如:

http://localhost:8080/example1/example/中国

正确的写法:

http://localhost:8080/example1/example/%E4%B8%AD%E5%9B%BD

并且我们建议URL中不要在PathInfo和QueryString同时使用非ASCII字符,比如

http://localhost:8080/example1/example/中国?name=中国

原因很简单:不同浏览器对URL中PathInfo和QueryString编码时采用的字符集不同,但应用服务器对URL通常会采用相同的字符集来解码。

2、我们建议URL中的URL Encode编码的字符集和网页的contentType的字符集采用相同的字符集,这样程序的实现就很简单,不用做复杂的编码转换。

java.net

类 URLEncoder

java.lang.Object  继承者 java.net.URLEncoder

public class URLEncoder

extends Object

HTML 格式编码的实用工具类。该类包含了将 String 转换为 application/x-www-form-urlencoded MIME 格式的静态方法。有关 HTML 格式编码的更多信息,请参阅 HTML 规范。

对 String 编码时,使用以下规则:

* 字母数字字符 "a" 到 "z"、"A" 到 "Z" 和 "0" 到 "9" 保持不变。

* 特殊字符 "."、"-"、"*" 和 "_" 保持不变。

* 空格字符 " " 转换为一个加号 "+"。

* 所有其他字符都是不安全的,因此首先使用一些编码机制将它们转换为一个或多个字节。然后每个字节用一个包含 3 个字符的字符串 "%xy" 表示,其中 xy 为该字节的两位十六进制表示形式。推荐的编码机制是 UTF-8。但是,出于兼容性考虑,如果未指定一种编码,则使用相应平台的默认编码。

例如,使用 UTF-8 编码机制,字符串 "The string ü@foo-bar" 将转换为 "The+string+%C3%BC%40foo-bar",因为在 UTF-8 中,字符 ü 编码为两个字节,C3 (十六进制)和 BC (十六进制),字符 @ 编码为一个字节 40 (十六进制)。

encode 原理

将组成中文的单个字符根据编码方式转换成二进制码并以16进制表示

每8位前加一个%,临床表现为%85%A2%86%A1这样的东东.

python url转码_深入浅出URL转码相关推荐

  1. Java线程池状态判断源码_深入浅出Java线程池:源码篇

    前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...

  2. java获取url中参数_获取url参数(java / js)

    (1)js // 获取url参数 function getQueryString(url, name) { console.log("url = " + url) console. ...

  3. 最新酒桌小游戏喝酒小程序源码_带流量主源码下载

    2022最新酒桌小游戏喝酒小程序源码_带流量主 喝酒神器3.6,我修改增加了广告位,根据文档直接替换即可,原版本没有广告位 直接上传源码到开发者端即可 通过后改广告代码,然后关闭广告展示提交,通过后打 ...

  4. 仿qq空间源码_【每日源码】一个Go语言编写的百度网盘客户端,强力推荐

    本月第7个源码推送 仿 Linux shell 文件处理命令的百度网盘命令行客户端. 功能简介: 目录 特色 编译/交叉编译 说明 下载/运行 说明 Windows Linux / macOS And ...

  5. MySQL中什么是码_数据库中的码是什么含义?

    展开全部 1.超码e68a843231313335323631343130323136353331333365656662: 超码是一个或多个属性的集合,这些属性可以让我们在一个实体集(所谓的实体集就 ...

  6. 客户要求提供源码_一对一直播源码定制:如你所愿,得你所想

    作者:布谷惠泽/来源:山东布谷鸟网络 移动互联网时代,产品的更新迭代层出不穷,视频直播行业的火爆,催生了不少直播程序开发公司,乘着这股火爆的劲头,一对主播源码也是一路繁华.一对一直播源码开发定制更是做 ...

  7. java生成冗余校验码_对循环冗余校验码CRC的理解

    模2加法 1+1=0, 0+1=1, 1+0=1, 0+0=0 模2减法 1-1=0, 0-1=1, 1-0=1, 0-0=0 相当于二进制中的逻辑异或运算.也就是比较后两者对应位相同则结果为&quo ...

  8. python下载文件保存_从URL下载文件并将其保存在Python文件夹中

    尝试使用stream选项:import os import requests def download(url: str, dest_folder: str): if not os.path.exis ...

  9. 调用python接口并画图_【PySpark源码解析】教你用Python调用高效Scala接口

    点击 机器学习算法与Python学习 ,选择加星标 精彩内容不迷路 机器之心专栏 作者:汇量科技-陈绪 众所周知,Spark 框架主要是由 Scala 语言实现,同时也包含少量 Java 代码.Spa ...

最新文章

  1. mac设置计算机用户名,如何更改macbook用户名_高手教你更改macbook用户名的方法-系统城...
  2. Android学习资源网站
  3. jms.jar 2.0_JMS 2.0中JMSContext的类型
  4. C ++或Java,高频交易哪个更快?
  5. silence丶你的名字
  6. while用法_语法宝典:连词while的四种用法,你都学会了吗?
  7. etmvc mysql乱码_Etmvc学习文档
  8. linux查看java虚拟机内存_深入理解java虚拟机(linux与jvm内存关系)
  9. 【金融工程实验】【matlab】使用candle函数画日均k线图
  10. linux命令行关机 密码,[ Linux 基本命令 001 ] 登陆,登出,重启,关机
  11. 多元统计分析基于r课后答案_多元统计分析课后练习答案.doc
  12. 苹果iBoot源代码
  13. 【微信商城小程序怎么弄】微信商城小程序开发的基本流程
  14. Javascript飘窗代码
  15. 安卓初学者笔记(四):用白话讲明白Activity是什么
  16. ODL中版本变化引起包位置的变化
  17. win10蓝牙android上网,Win10开启蓝牙移动热点共享上网教程
  18. qt5版本管理git_Building Qt 5 from Git/zh
  19. 计算机网络延展-桥接器(网桥)
  20. 判断用户输入的数为正数还是负数

热门文章

  1. 【开源周荐】分布式配置管理神器Qihoo360/QConf入门指北(部署、配置、使用、架构原理)
  2. 【springboot系列】这样优化Spring Boot,启动速度快到飞起!
  3. linux常用命令及运维工具汇总
  4. 吉林大学外国语学院外国语言学及应用语言学专业考研上岸经验分享
  5. 关于MMAPI的学习
  6. 编写python程序计算所有个位数大于十位数的两位数的和_大学计算机及程序设计Ⅲ(曹进)-中国大学mooc-题库零氪...
  7. APS生产排单软件帮助锅炉企业升级
  8. Anti-Aliasing抗锯齿 SSAA MSAA FXAA三维游戏抗锯齿技术浅谈
  9. c语言ln函数复数怎么使用,如何使用C中的复数?
  10. maniadmin 后台管理模版 HTML