html

html文件本身是有编码格式的,就和普通的ascii文件一样。

同时,html能够指定编码元数据,告诉浏览器要以哪种编码形式读取自己(注意:charset指定的字符集一定要是这个文件本身的字符集,否则读取就乱了)

<meta charset="UTF-8">

响应头Content-type可以指定编码格式:Content-Type: text/html; charset=UTF-8

实际上浏览器在解析html文件时,首先是看响应头中指定的编码格式,如果指定了先按这个格式读取html文件,如果html文件中又指定了不同的charset,那会重新按这个格式再读取一遍,很显然太浪费时间了。

如果都没有指定,那浏览器会根据一些规则进行嗅探、猜测,可能就产生乱码了。

所以最好是响应头和meta中都指定一样的charset。

url

现代浏览器,在输入url后可以自动对中文进行urlencode,其中url部分默认使用utf-8编码。

比如:http://localhost:8080/你好,输入后自动得到http://localhost:8080/%E4%BD%A0%E5%A5%BD (从浏览器中复制出来才能看到,或者查看request header)

既然浏览器进行了编码,那服务端必然要解码,比如tomcat,如果设置的URIEncoding不匹配,解码得到乱码,会报找不到文件的错误。

html文件中的超链接,不管html的charset是什么编码,url中协议、端口、路径依然采用utf-8编码。但是后面的查询字符串的urlencode是以html文件中的编码格式为基准的。

form

form表单,提交时的编码问题

get

get提交时,默认的encryptapplication/x-www-form-urlencoded

此时会将非字母input,进行urlencode,字符集使用html的charset。

当然也可以单独指定:

form标签可以持有accept-charset 属性,这个值就是input进行编码的charset,如果指定多个,会依次查看浏览器是否支持,如果遇到支持的就使用这个。

<form action=”xxx.jsp” method=”get” accept-charset=”gbk,utf-8”>...</form>

post

post默认也是使用application/x-www-form-urlencoded提交数据,编码规则和get完全相同。

比如tomcat,get请求时由于参数是在url中,会被URIEncoding设置的编码直接解析,所以只要这里设置成功了,get请求就不会乱码。

但是post请求,参数是在body中,此时URIEncoding是处理不了body的,需要在业务逻辑中实现。


encrypt还有一个值是multipart/form-data,只有post的情况才有效

比如上传文件,那必须使用这个类型。

此时的text input不是字母类型的字符,也不会进行urlencode,传输时仅仅传输对应的二进制码(根据当前页面的charset或accept-charset)。

而上传的文件,文件名的二进制码也是根据页面charset或accept-charset得到。文件本身的内容和文件本身的字符集相关,只是单纯的传输内容的字节流而已。

js

涉及到的字符集:

  1. html文件、js文件本身的字符集

  2. html文件meta指定的字符集

  3. 请求头和响应头中设置的字符集

1和2必然要一致。3中设置的字符集是告诉浏览器或服务端我提供的内容是这个字符集,对方就会首先以这个字符集读取内容。

get

js原生请求

参数自动urlencode,根据html页面的字符集charset

var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8080/urltest/my2?name=我', true)
xhr.send()

ajax请求

如果将参数写在data中,经测试,一直都是以utf-8发送

写在url中,根据html页面的字符集charset

$.ajax({
    url: 'http://localhost:8080/urltest/my1',
    type: 'GET',
    contentType: 'application/x-www-form-urlencoded;charset=gbk',
    data: { name: '我' },
})

post

js原生请求

设置为application/x-www-form-urlencoded也不会自动编码,直接发送,字符集强制转化为UTF-8。如果content-type设置了其他字符集,可以通过工具查看request header,也会变成UTF-8,虽然content-type的设置并不影响你提供的内容具体是什么字符集,这只是一种约定、通知,但是从请求头中也能看出,被强制转成了UTF-8。

var xhr = new XMLHttpRequest()
xhr.open('POST', 'http://localhost:8080/urltest/my2', true)
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=UTF-8')
xhr.send('name=我')

ajax请求

同上,唯一区别是使用application/x-www-form-urlencoded格式时,会自动编码,按UTF-8格式。

使用text/plain时也会自动urlencode

==综上:不要设置些乱七八糟的字符集,在需要urlencode的时候,主动进行,不要让浏览器干涉,否则结果可能非预期。最好在需要的地方都使用utf-8。==

spring boot中

spring boot 在需要解码的时候,默认会以utf-8的格式解码。 不管是使用@RequestParam还是直接以bean的形式接收都会自动解码,这2种形式只支持application/x-www-form-urlencoded格式的数据。

@RequestBody支持application/jsontext/plain,区别是json格式会被转化为相关bean,且不会解码。

text/plain格式能转化成String,并且也不会解码,会完整的得到整个传过来的字符串,比如name=我,如果传过来的值进行了urlencode,也会得到完成的name=%E6%88%91