Web | 浏览器、服务器间的编解码问题

前提概要:编码和解码采用的字符集不同就会出现乱码。那么浏览器到服务器,服务器到浏览器之间通信过程中有过哪些编解码过程?默认编解码的字符集是什么?如何设置?下文将从这些方面进行详细说明!

常用字符集:

  1. GB2313:中国制定的字符集,每个中文占两个字节。
  2. GBK:是GB2312的扩展,向下兼容GB2312。
  3. ISO8859-1:单字节,不支持中文。
  4. UTF-8:支持中文,每个中文三个字节。

默认字符集
操作系统"Windows"中文版的默认编码GB2312(cmd命令输入chcp可以查看,936代表GB2312)

一、浏览器 - - -》服务器

1. 浏览器的编码

1.1 url中编码

1. 为什么会出现url编码?
一般来说,URL只能使用英文字母、阿拉伯数字和某些标点符号,不能使用其他文字和符号。比如,世界上有英文字母的网址"http://www.abc.com",但是没有希腊字母的网址"http://www.aβγ.com"。这是因为网络标准RFC 1738做了硬性规定:只有字母和数字[0-9a-zA-Z]、一些特殊符号"$-_.+!*'(),"[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL
这意味着,如果URL中有汉字,就必须编码后使用。但是麻烦的是,RFC 1738没有规定具体的编码方法,而是交给应用程序(浏览器)自己决定。这导致"URL编码"成为了一个混乱的领域。

2. 什么是url编码?
将中文等按某一字符集来编码,然后将其十六进制每两个用一个%隔开,如:中国 —》%E4%B8%AD%E5%9B%BD;当然像谷歌和火狐浏览器地址栏中直接显示的中文,抓包可以看到编码后的。

3. url组成
url组成:域名:端口/contextPath/servletPath/pathInfo?queryString。下面主要将url从两部分说明:1. 资源路径(pathInfo);2. 查询参数(queryString)


1.2 个人结论

下文对地址栏中url的资源地址和请求参数以get和post两种请求方式,网页中的请求和直接在地址栏输入时不同浏览器编码方式:不同浏览器中URL的编码方式

  1. 火狐和谷歌浏览器的默认编码为utf-8
  2. 如果直接在地址栏中输入时,pathInfo(路径信息)和queryString(请求参数)中的都是采用浏览器的默认编码方式;
  3. 如果是在html页面中的请求,如 超链接:<a href="/中国/a?str=中国">、表单提交。pathInfo(前一个中国)仍然采用浏览器的默认编码,而queryString(后一个中国)/表单数据(作为post请求的请求体或者get请求url后面的参数)则采用页面设置的编码。


//html页面
<form action="中国.do?contry=中国" method="post" enctype="multipart/form-data">
    <table>
        <tr>
            <td>姓名</td>
            <td><input name="name" type="text"></td>
            <td>年龄</td>
            <td><input name="age" type="text"></td>
        </tr>
        <tr><input type="submit" value="提交"></tr>
    </table>
</form>



2. 服务器端如何解码?

服务器端默认解码和编码方式是 ISO-8859-1。当然要服务器端设置相同的解码字符集才不会乱码,具体设置如下:

2.1 服务器软件中设置(tomcat为例)

修改服务器端对url参数的默认编码:
在tomcat的server.xml中,设置<Connector ….>元素的属性URIEncoding="UTF-8"即可。(默认没有设置此属性)。
例如:<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" URIEncoding="UTF-8"/>

注意:
1、设置<Connector ….>元素的属性useBodyEncodingForURI="true",意思是请求体和url参数使用相同的编码格式。通过设置这两个属性,既可以解决get方式的乱码,又可以解决post方式的乱码。
2、通过修改server.xml指定服务器对get和post统一按照utf-8解码,要求tomcat管理下的所有web应用都要使用utf-8编码,即所有的jsp、html页面都使用utf-8编码。


2.2 通过request.setCharacterEncoding("utf-8”)即可解决乱

request.setCharacterEncoding("utf-8”) 只对请求体里面的参数有效;如果参数跟在请求行中的url后边,它就无能为力了。因此这个可以适用post请求。但是不适用于url中(资源地址或参数中)含中文的get请求和url也带参数的post请求。

2.3 借助getBytes(),反编码

既然服务器会进行iso-8859-1解码,那么我就让它这样解码,当其将这种解码的结果封装在request对象中时我可以通过getBytes()来获取其原始字节码,然后再编码,具体如下:

String name = request.getParameter("name”);//得到乱码
//name.getBytes("iso-8859-1"):采用iso-8859-1还原到字节码;然后再对字节码用utf-8来编码得到正确的字符串。
name = new String(name.getBytes("iso-8859-1"),"utf-8);

注意: name.getBytes();如果不指定编码,默认按照gb2312进行编码。

2.4 在springmvc中采用CharacterEncodingFilter拦截器

当post请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤。
我想搞清楚的是这个是在服务器按iso-8859-1解码后,然后这个拦截器要求其按iso-8859-1还原字节码然后再用’utf-8’的吗?
他对请求体参数和url中的参数都有效吗?

web.xml中的配置:

<filter>
	<filter-name>CharacterEncodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
	<init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
   </init-param>
</filter>
<filter-mapping>
	<filter-name>CharacterEncodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

结合CharacterEncodingFilter源码解读
这里的forceEncoding是决定其两个成员变量private boolean forceRequestEncoding = false; private boolean forceResponseEncoding = false;的值,默认为false,如果为true则对请求或响应设置如下:request.setCharacterEncoding(encoding);response.setCharacterEncoding(encoding);
我想到目前,已经解决了我前面的问题!根据不同配置可以对响应和请求做这两个操作,但这样设置的局限性前面也提到过。request.setCharacterEncoding(encoding);只对请求体有用(不过好像get方式的编码问题jdk已经解决了);response.setCharacterEncoding(encoding); 只规定了服务器端的编码字符集而没有告诉浏览器。



package org.springframework.web.filter;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

public class CharacterEncodingFilter extends OncePerRequestFilter {

	@Nullable
	private String encoding;

	private boolean forceRequestEncoding = false;

	private boolean forceResponseEncoding = false;


	public CharacterEncodingFilter() {
	}


	public CharacterEncodingFilter(String encoding) {
		this(encoding, false);
	}

	public CharacterEncodingFilter(String encoding, boolean forceEncoding) {
		this(encoding, forceEncoding, forceEncoding);
	}
	
	public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) {
		Assert.hasLength(encoding, "Encoding must not be empty");
		this.encoding = encoding;
		this.forceRequestEncoding = forceRequestEncoding;
		this.forceResponseEncoding = forceResponseEncoding;
	}

	public void setEncoding(@Nullable String encoding) {
		this.encoding = encoding;
	}

	@Nullable
	public String getEncoding() {
		return this.encoding;
	}
/*
****************************************************
~~~~~~~~上面配置的forceEncoding就是设置的这个属性这个就是属性~~~~~~
****************************************************
*/
	public void setForceEncoding(boolean forceEncoding) {
		this.forceRequestEncoding = forceEncoding;
		this.forceResponseEncoding = forceEncoding;
	}



	public void setForceRequestEncoding(boolean forceRequestEncoding) {
		this.forceRequestEncoding = forceRequestEncoding;
	}

	public boolean isForceRequestEncoding() {
		return this.forceRequestEncoding;
	}

	public void setForceResponseEncoding(boolean forceResponseEncoding) {
		this.forceResponseEncoding = forceResponseEncoding;
	}

	public boolean isForceResponseEncoding() {
		return this.forceResponseEncoding;
	}


	@Override
	protected void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		String encoding = getEncoding();
		if (encoding != null) {
			if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
				request.setCharacterEncoding(encoding);
			}
			if (isForceResponseEncoding()) {
				response.setCharacterEncoding(encoding);
			}
		}
		filterChain.doFilter(request, response);
	}

}



二、服务器 - - -》浏览器

1. 服务器编码

前面也说了,服务器端默认解码和编码方式是 ISO-8859-1,当然我们是可以设置的!

1.1 设置响应的编码

使用:response.setContentType("text/html;charset=utf-8");;其是response.setCharacterEncoding("utf-8"); (设置响应流的编码) 和 response.setHeader("content-type","text/html;charset=utf-8");(设置响应数据的格式,告诉浏览器我的响应体MIME类型和我采用的编码)的结合。





参考:
浏览器到服务器间的编解码问题1

浏览器到服务器间的编解码问题2
浏览器到服务器间的编解码问题3

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值