编码空格问题

问题描述

因为入参会有begin with作为参数,在POSTMAN中对入参进行encodeURIComponent编码时,空格编码为“%20”,而在代码中对空格进行编码则编码为“+”,导致mock的数据不一致。

产生原因

W3C标准规定,当Content-Type为application/x-www-form-urlencoded时,URL(Uniform Resource Locator)中查询参数名和参数值中空格要用加号+替代,所以几乎所有使用该规范的浏览器在表单提交后,URL查询参数中空格都会被编成加号+。而在另一份规范(RFC 2396)里, URI(Uniform Resource Identifier)里的保留字符都需转义成%HH格式(Section 3.4 Query Component),因此空格会被编码成%20,加号+本身也作为保留字而被编成%2B,对于某些遵循RFC 2396标准的应用来说,它可能不接受查询字符串中出现加号+,认为它是非法字符。所以一个安全的举措是URL中统一使用%20来编码空格字符。

举个例子,下面的请求参数condition里有start with内容,空格通过postman的encodeURIComponent

如下示例所示,URLEncoder的encode方法可以把字符串中的空格编码为"+",然后我们再通过替换的方式把空格替换成%20,使得和mock数据保持一致,解码阶段"+"或"%20"均能被解码成空格。

public class BlankEncodeTest {
    public static void main(String[] args) {
        try {
            // 编码阶段
            String uri = "start with";
            String encodeUri = URLEncoder.encode(uri, "utf-8");
            System.out.println(encodeUri);  // start+with
            encodeUri = encodeUri.replaceAll("\\+", "%20");
            System.out.println(encodeUri);
            // 解码阶段
            String decodeUri = URLDecoder.decode(encodeUri, "utf-8");
            System.out.println(decodeUri);  // start with
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

其他

编码格式有多种,除了utf-8还有gbk,那么GBK的编码字节流和UTF-8的字节流如何实现互转呢?下面直接看一个小demo,GBK编码字节流 ——> UTF-8编码字节流

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
 * GBK编码字节流 转换为 UTF-8编码字节流
 */
public class GBK2UTF8 {
    public static void main(String[] args) {
        String[] str = new String[]{"中国", "original language"};
        compareGBKAndUTF8(str);
        convertGBK2UTF8(str[0]);
    }

    private static void compareGBKAndUTF8(String[] str) {
        Arrays.asList(str).forEach(s -> {
            // 默认UTF-8
            byte[] src = s.getBytes();
            try {
                // 以GBK编码方式创建对象会出现乱码
                String gbkStr = new String(src, "GBK");
                String utf8Str = new String(src, StandardCharsets.UTF_8);
                System.out.println("gbk编码方式 : " + gbkStr + "\nutf-8编码方式 : " + utf8Str);
            } catch (UnsupportedEncodingException e) {
                System.out.println("The Character Encoding is not supported.");
            }
        });
    }

    private static void convertGBK2UTF8(String str) {
        try {
            System.out.println("=============== UTF-8 转 GBK =================");
            String gbkStr = new String(str.getBytes(), "GBK");
            System.out.println("after gbk encode string is :" + gbkStr);
            System.out.println("=============== GBK 转 UTF-8 =================");
            byte[] out = gbkStr.getBytes(StandardCharsets.UTF_8);
            String utf8Str = new String(out, StandardCharsets.UTF_8);
            System.out.println("after gbk string convert utf-8 is :" + utf8Str);
        } catch (UnsupportedEncodingException e) {
            System.out.println("The Character Encoding is not supported.");
        }
    }
}

输出结果如下,

但是我们发现中文是乱码,那是由于编码方式分为很多种,下面是主要的几种编码方式:

  • UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。
  • GBK编码:一个英文字符占一个字节,一个中文占两个字节。
  • Unicode编码:一个英文占两个字节,一个中文(含繁体)也占两个字节。
  • ASCII码:一个英文字母(不分大小写)占一个字节,一个中文占两个字节。

String类型的编码方式是与JVM编码方式和本机操作系统默认字符集有关的,找到Charset类的defaultCharset静态方法就知道本机默认的字符集是UTF-8。

    public static Charset defaultCharset() {
        if (defaultCharset == null) {
            synchronized (Charset.class) {
                String csn = AccessController.doPrivileged(
                    new GetPropertyAction("file.encoding"));
                Charset cs = lookup(csn);
                if (cs != null)
                    defaultCharset = cs;
                else
                    defaultCharset = forName("UTF-8");
            }
        }
        return defaultCharset;
    }

找到原因,那么字符串编码方式怎么转就都容易了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值