Search code examples
javaspringspring-mvcfastjson

Java:Alibaba Fastjson decodeUTF8 return:Index out of range -1 from springmvc?


@wenshao I have a website using springmvc to request other api interface. I using the HttpHelper.doPost method to request.

public static String doPost(String url, String json,String... args) throws Exception {
    URL localURL = new URL(url);

    URLConnection connection = localURL.openConnection();
    HttpURLConnection httpURLConnection = (HttpURLConnection) connection;

    String encoding = getEncoding(args);
    int connectTimeout = getConnectTimeout(args);
    int readTimeout = getReadTimeout(args);

    httpURLConnection.setDoOutput(true);
    httpURLConnection.setRequestMethod("POST");
    httpURLConnection.setRequestProperty("Accept-Charset", encoding);
    httpURLConnection.setConnectTimeout(connectTimeout);
    httpURLConnection.setReadTimeout(readTimeout);
    httpURLConnection.setRequestProperty("Content-Type", "application/json");
    httpURLConnection.setRequestProperty("Content-Length", String.valueOf(json.length()));

    OutputStream outputStream = null;
    OutputStreamWriter outputStreamWriter = null;
    InputStream inputStream = null;
    InputStreamReader inputStreamReader = null;
    BufferedReader reader = null;
    StringBuffer resultBuffer = new StringBuffer();
    String tempLine;

    try {
        outputStream = httpURLConnection.getOutputStream();
        outputStreamWriter = new OutputStreamWriter(outputStream);

        outputStreamWriter.write(json);
        outputStreamWriter.flush();

        if (httpURLConnection.getResponseCode() >= 400) {
            inputStream = httpURLConnection.getErrorStream();
        } else {
            inputStream = httpURLConnection.getInputStream();
        }
        inputStreamReader = new InputStreamReader(inputStream, encoding);
        reader = new BufferedReader(inputStreamReader);

        while ((tempLine = reader.readLine()) != null) {
            resultBuffer.append(tempLine);
        }
    } finally {
        close(outputStreamWriter, outputStream, reader, inputStreamReader, inputStream);
    }
    return String.valueOf(resultBuffer);
}

It works fine if I use unit test to request api using the code above.But when I use springmvc action to request it ,it give me the server error 500:index out of range -1 from the api interface.the below code always return -1 when I use springmvc to request it.

public static int decodeUTF8(byte[] sa, int sp, int len, char[] da) {
    final int sl = sp + len;
    int dp = 0;
    int dlASCII = Math.min(len, da.length);

    // ASCII only optimized loop
    while (dp < dlASCII && sa[sp] >= 0)
        da[dp++] = (char) sa[sp++];

    while (sp < sl) {
        int b1 = sa[sp++];
        if (b1 >= 0) {
            // 1 byte, 7 bits: 0xxxxxxx
            da[dp++] = (char) b1;
        } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
            // 2 bytes, 11 bits: 110xxxxx 10xxxxxx
            if (sp < sl) {
                int b2 = sa[sp++];
                if ((b2 & 0xc0) != 0x80) { // isNotContinuation(b2)
                    return -1;
                } else {
                    da[dp++] = (char) (((b1 << 6) ^ b2)^
                                   (((byte) 0xC0 << 6) ^
                                    ((byte) 0x80 << 0)));
                }
                continue;
            }
            return -1;
        } else if ((b1 >> 4) == -2) {
            // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
            if (sp + 1 < sl) {
                int b2 = sa[sp++];
                int b3 = sa[sp++];
                if ((b1 == (byte) 0xe0 && (b2 & 0xe0) == 0x80) //
                    || (b2 & 0xc0) != 0x80 //
                    || (b3 & 0xc0) != 0x80) { // isMalformed3(b1, b2, b3)
                    return -1;
                } else {
                    char c = (char)((b1 << 12) ^
                                      (b2 <<  6) ^
                                      (b3 ^
                                      (((byte) 0xE0 << 12) ^
                                      ((byte) 0x80 <<  6) ^
                                      ((byte) 0x80 <<  0))));
                    boolean isSurrogate =  c >= Character.MIN_SURROGATE && c < (Character.MAX_SURROGATE + 1);
                    if (isSurrogate) {
                        return -1;
                    } else {
                        da[dp++] = c;
                    }
                }
                continue;
            }
            return -1;
        } else if ((b1 >> 3) == -2) {
            // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
            if (sp + 2 < sl) {
                int b2 = sa[sp++];
                int b3 = sa[sp++];
                int b4 = sa[sp++];
                int uc = ((b1 << 18) ^
                          (b2 << 12) ^
                          (b3 <<  6) ^
                          (b4 ^
                           (((byte) 0xF0 << 18) ^
                           ((byte) 0x80 << 12) ^
                           ((byte) 0x80 <<  6) ^
                           ((byte) 0x80 <<  0))));
                if (((b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 || (b4 & 0xc0) != 0x80) // isMalformed4
                    ||
                    // shortest form check
                    !Character.isSupplementaryCodePoint(uc)) {
                    return -1;
                } else {
                    da[dp++] =  (char) ((uc >>> 10) + (Character.MIN_HIGH_SURROGATE - (Character.MIN_SUPPLEMENTARY_CODE_POINT >>> 10))); // Character.highSurrogate(uc);
                    da[dp++] = (char) ((uc & 0x3ff) + Character.MIN_LOW_SURROGATE); // Character.lowSurrogate(uc);
                }
                continue;
            }
            return -1;
        } else {
            return -1;
        }
    }
    return dp;
}

the normal will return the actual length of my request json but the spring will not. broken request

correct request using postman to request

the correct length

Edit: I found the reason why the error occurred.Because I passed the Chinese in request json.how can i solve it?


Solution

  • I have solved it. correct code:

    new String(request.getRealName().getBytes(),"utf-8")
    

    wrong code:

    new String(request.getRealName().getBytes("utf-8"),"utf-8")
    

    because my system's default encoding is gbk not utf-8.