[alibaba/fastjson]当Base64字符串中的斜杠/被转义为\/后,解析为byte[]有问题

2025-11-11 385 views
4

fastjson-1.2.47,当Base64字符串中的斜杠/被转义为\/后,解析为byte[]有问题。

@JSONType
public class TestEntity {
    @JSONField(name="type")
    public int type;

    @JSONField(name="data")
    public byte[] data;
}

如下调用:

String j1 = "{\"type\":800,\"data\":\"HuYgMIxwfqdtvOJNv6kK025g5fh3yFHI2kaByO7udKk6FOBC3PGRWkGfwV0\\/vWQW6roN5ftKDHFZ3PWl0715OYue0rZj\\/VwrNsMvIL4MqTUNBBUGFU9SgZu87ss7RqmyijH6\\/sM968cK1Dv5U7Rrw79idl\\/hW8SILLn1YXvUa60=\"}";
try {
    JSONObject y1 = JSON.parseObject(j1);
    Log.e(TAG, "y1=" + y1);

    TestEntity y2 = y1.toJavaObject(TestEntity.class);
    Log.e(TAG, "y2=" + JSON.toJSONString(y2));

    TestEntity y3 = JSON.parseObject(j1, TestEntity.class);
    Log.e(TAG, "y3=" + JSON.toJSONString(y3));
} catch (Exception e) {
    // TODO: handle exception
    Log.e(TAG, "xx", e);
}

结果:

04-27 08:21:11.907: E/xx(14883): y1={"data":"HuYgMIxwfqdtvOJNv6kK025g5fh3yFHI2kaByO7udKk6FOBC3PGRWkGfwV0/vWQW6roN5ftKDHFZ3PWl0715OYue0rZj/VwrNsMvIL4MqTUNBBUGFU9SgZu87ss7RqmyijH6/sM968cK1Dv5U7Rrw79idl/hW8SILLn1YXvUa60=","type":800}
04-27 08:21:11.924: E/xx(14883): y2={"data":"HuYgMIxwfqdtvOJNv6kK025g5fh3yFHI2kaByO7udKk6FOBC3PGRWkGfwV0/vWQW6roN5ftKDHFZ3PWl0715OYue0rZj/VwrNsMvIL4MqTUNBBUGFU9SgZu87ss7RqmyijH6/sM968cK1Dv5U7Rrw79idl/hW8SILLn1YXvUa60=","type":800}
04-27 08:21:11.927: E/xx(14883): y3={"data":"HuYgMIxwfqdtvOJNv6kK025g5fh3yFHI2kaByO7udKk6FOBC3PGRWkGf/////vWQW6roN5ftKDHFZ3PWl0715OYue0rZ///VwrNsMvIL4MqTUNBBUGFU9SgZu87ss7Rqmyij////sM968cK1Dv5U7Rrw79id///hW8SILLn1YXvU","type":800}

其中y1和y2是正确的,而y3是错误的。

回答

5

而且采用下面的方式调用:

public final class MyBlobDeserializer implements ObjectDeserializer {

    @SuppressWarnings("unchecked")
    @Override
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        Object val = parser.parse();
        if (val == null) {
            return null;
        }

        return (T) TypeUtils.castToBytes(val);
    }

    @Override
    public int getFastMatchToken() {
        // TODO Auto-generated method stub
        return JSONToken.LITERAL_STRING;
    }
}

@JSONType
public class TestEntity2 {
    @JSONField(name="type")
    public int type;

    @JSONField(name="data", deserializeUsing=MyBlobDeserializer.class)
    public byte[] data;
}

TestEntity2 y4 = JSON.parseObject(j1, TestEntity2.class);
Log.e(TAG, "y4=" + JSON.toJSONString(y4));

得到的结果是正确的:

04-27 09:06:39.943: E/xx(17158): y4={"data":"HuYgMIxwfqdtvOJNv6kK025g5fh3yFHI2kaByO7udKk6FOBC3PGRWkGfwV0/vWQW6roN5ftKDHFZ3PWl0715OYue0rZj/VwrNsMvIL4MqTUNBBUGFU9SgZu87ss7RqmyijH6/sM968cK1Dv5U7Rrw79idl/hW8SILLn1YXvUa60=","type":800}
0

看起来是bug

1

从现象上看,Base64中的字符转义以后都不能正确解析。 比如把 =写为\u003d

2

另外,SerializerFeature.WriteSlashAsSpecial 对Base64(或其他方式)生成的字符串中的/不生效(生效可能会产生兼容性问题),不知道算不算bug。

6

'/'这个字符不应该需要转义啊,这个转义怎么来的?

7

有的JSON库原生不支持byte[] -> Base64就按下面的流程转换: byte[] -> Base64 Encoded String -> Escaped JSON String 就可能出现。

比如iOS客户端使用NSJSONSerialization, 由于NSJSONSerialization不支持NSData (相当于Java中的byte[]), 就得提前转为Base64字符串。

其他一些没有原生支持byte[]的JSON库,比如GSON也得提前转为Base64字符串。

5

跟了一下,Base64 decode之前没有对待解码字符串进行转义处理导致出现的问题,我提个PR吧。