코드 변환 문 제 를 해결 하 는 과정 을 기록 합 니 다.-springboot tomcat 소스 코드 를 수정 합 니 다.%변환 되 지 않 아 파 라 메 터 를 받 을 수 없습니다.

배경
자바 로 PHP 프로젝트 를 재 구성 합 니 다.예전 에는 인터페이스 디자인 이 합 리 적 이지 않 았 기 때문에 다양한 매개 변수 가 날 아 다 녔 습 니 다.자바 코드 를 점차적으로 대체 하고 온라인 업무 에 영향 을 주지 않 기 위해 서 입 니 다.첫 번 째 단 계 는 매개 변수 와 인터페이스 방식 이 변 하지 않 는 다 는 것 을 결정 하 는 것 도 이 문 제 를 일 으 켰 다.
문제 가 생기다
같은 인터페이스:
go->자바 와 클 라 이언 트->자바,Content-Type 은 모두 application/x-www-form-urlencoded 이지 만 클 라 이언 트 가 인 자 를 바 꾸 었 지만 유일한%는 바 꾸 지 않 았 습 니 다.
예 를 들 어{"param":"%"}정확 한 코드 는%7B%22param%22%3A%22%25%22%7D 이지 만%7B%22param%22%3A%22%22%7D 로 바 뀌 었 습 니 다.
배경 에서 데 이 터 를 받 지 못 합 니 다.
3.해결 방안:
tomcat 에 로그 오류 가 발생 합 니 다(debug 모드 를 켜 야 볼 수 있 습 니 다):org.apache.tomcat.util.http.Parameters:173 [http-nio-20977-exec-1]  -  Character decoding failed. Parameter 
첫 번 째:클 라 이언 트(안 드 로 이 드)는 코드 를 수정 하고 모든 데 이 터 를 전의 해 야 합 니 다.이것 은 클 라 이언 트 를 강제로 업그레이드 해 야 합 니 다(포기)
두 번 째:자바 서버 tomcat 소스 코드 수정
Parameters 라 는 클래스 에 들 어가 코드 를 연구 한 결과 processParameters 라 는 방법 에서%가 분석 되 지 않 았 습 니 다.코드 는 다음 과 같 습 니 다.
private void processParameters(byte bytes[], int start, int len, Charset charset) {

        if(log.isDebugEnabled()) {
            log.debug(sm.getString("parameters.bytes",
                    new String(bytes, start, len, DEFAULT_BODY_CHARSET)));
        }

        int decodeFailCount = 0;

        int pos = start;
        int end = start + len;

        while(pos < end) {
            int nameStart = pos;
            int nameEnd = -1;
            int valueStart = -1;
            int valueEnd = -1;

            boolean parsingName = true;
            boolean decodeName = false;
            boolean decodeValue = false;
            boolean parameterComplete = false;

            do {
                switch(bytes[pos]) {
                    case '=':
                        if (parsingName) {
                            // Name finished. Value starts from next character
                            nameEnd = pos;
                            parsingName = false;
                            valueStart = ++pos;
                        } else {
                            // Equals character in value
                            pos++;
                        }
                        break;
                    case '&':
                        if (parsingName) {
                            // Name finished. No value.
                            nameEnd = pos;
                        } else {
                            // Value finished
                            valueEnd  = pos;
                        }
                        parameterComplete = true;
                        pos++;
                        break;
                    case '%':
                    case '+':
                        // Decoding required
                        if (parsingName) {
                            decodeName = true;
                        } else {
                            decodeValue = true;
                        }
                        pos ++;
                        break;
                    default:
                        pos ++;
                        break;
                }
            } while (!parameterComplete && pos < end);

            if (pos == end) {
                if (nameEnd == -1) {
                    nameEnd = pos;
                } else if (valueStart > -1 && valueEnd == -1){
                    valueEnd = pos;
                }
            }

            if (log.isDebugEnabled() && valueStart == -1) {
                log.debug(sm.getString("parameters.noequal",
                        Integer.valueOf(nameStart), Integer.valueOf(nameEnd),
                        new String(bytes, nameStart, nameEnd-nameStart, DEFAULT_BODY_CHARSET)));
            }

            if (nameEnd <= nameStart ) {
                if (valueStart == -1) {
                    // &&
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("parameters.emptyChunk"));
                    }
                    // Do not flag as error
                    continue;
                }
                // &=foo&
                UserDataHelper.Mode logMode = userDataLog.getNextMode();
                if (logMode != null) {
                    String extract;
                    if (valueEnd > nameStart) {
                        extract = new String(bytes, nameStart, valueEnd - nameStart,
                                DEFAULT_BODY_CHARSET);
                    } else {
                        extract = "";
                    }
                    String message = sm.getString("parameters.invalidChunk",
                            Integer.valueOf(nameStart),
                            Integer.valueOf(valueEnd), extract);
                    switch (logMode) {
                        case INFO_THEN_DEBUG:
                            message += sm.getString("parameters.fallToDebug");
                            //$FALL-THROUGH$
                        case INFO:
                            log.info(message);
                            break;
                        case DEBUG:
                            log.debug(message);
                    }
                }
                setParseFailedReason(FailReason.NO_NAME);
                continue;
                // invalid chunk - it's better to ignore
            }

            tmpName.setBytes(bytes, nameStart, nameEnd - nameStart);
            if (valueStart >= 0) {
                tmpValue.setBytes(bytes, valueStart, valueEnd - valueStart);
            } else {
                tmpValue.setBytes(bytes, 0, 0);
            }

            // Take copies as if anything goes wrong originals will be
            // corrupted. This means original values can be logged.
            // For performance - only done for debug
            if (log.isDebugEnabled()) {
                try {
                    origName.append(bytes, nameStart, nameEnd - nameStart);
                    if (valueStart >= 0) {
                        origValue.append(bytes, valueStart, valueEnd - valueStart);
                    } else {
                        origValue.append(bytes, 0, 0);
                    }
                } catch (IOException ioe) {
                    // Should never happen...
                    log.error(sm.getString("parameters.copyFail"), ioe);
                }
            }

            try {
                String name;
                String value;

                if (decodeName) {
                    urlDecode(tmpName);
                }
                tmpName.setCharset(charset);
                name = tmpName.toString();

                if (valueStart >= 0) {
                    if (decodeValue) {
                        urlDecode(tmpValue);
                    }
                    tmpValue.setCharset(charset);
                    value = tmpValue.toString();
                } else {
                    value = "";
                }

                try {
                    addParameter(name, value);
                } catch (IllegalStateException ise) {
                    // Hitting limit stops processing further params but does
                    // not cause request to fail.
                    UserDataHelper.Mode logMode = maxParamCountLog.getNextMode();
                    if (logMode != null) {
                        String message = ise.getMessage();
                        switch (logMode) {
                            case INFO_THEN_DEBUG:
                                message += sm.getString(
                                        "parameters.maxCountFail.fallToDebug");
                                //$FALL-THROUGH$
                            case INFO:
                                log.info(message);
                                break;
                            case DEBUG:
                                log.debug(message);
                        }
                    }
                    break;
                }
            } catch (IOException e) {
                setParseFailedReason(FailReason.URL_DECODING);
                decodeFailCount++;
                if (decodeFailCount == 1 || log.isDebugEnabled()) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("parameters.decodeFail.debug",
                                origName.toString(), origValue.toString()), e);
                    } else if (log.isInfoEnabled()) {
                        UserDataHelper.Mode logMode = userDataLog.getNextMode();
                        if (logMode != null) {
                            String message = sm.getString(
                                    "parameters.decodeFail.info",
                                    tmpName.toString(), tmpValue.toString());
                            switch (logMode) {
                                case INFO_THEN_DEBUG:
                                    message += sm.getString("parameters.fallToDebug");
                                    //$FALL-THROUGH$
                                case INFO:
                                    log.info(message);
                                    break;
                                case DEBUG:
                                    log.debug(message);
                            }
                        }
                    }
                }
            }

            tmpName.recycle();
            tmpValue.recycle();
            // Only recycle copies if we used them
            if (log.isDebugEnabled()) {
                origName.recycle();
                origValue.recycle();
            }
        }

        if (decodeFailCount > 1 && !log.isDebugEnabled()) {
            UserDataHelper.Mode logMode = userDataLog.getNextMode();
            if (logMode != null) {
                String message = sm.getString(
                        "parameters.multipleDecodingFail",
                        Integer.valueOf(decodeFailCount));
                switch (logMode) {
                    case INFO_THEN_DEBUG:
                        message += sm.getString("parameters.fallToDebug");
                        //$FALL-THROUGH$
                    case INFO:
                        log.info(message);
                        break;
                    case DEBUG:
                        log.debug(message);
                }
            }
        }
    }

트 레이스 byte 배열 의 출처 는 Request 류 에서 byte 배열 이 최종 적 으로 postdata 에서 온 것 을 발 견 했 기 때문에 먼저 postdata 를 전의 하여 교체 합 니 다.
                if(null != postData){
                    String param = new String(postData);
                    if(param.contains("%%")){
                        param = param.replace("%%","%25%");
                        postData = param.getBytes();
                        len += 2;
                    }
                }

Request 클래스 의 3212 줄 에 이 코드 를 추가 하면 실행 중 문제 가 해결 되 지 않 습 니 다.첫 번 째 요청 은 post Data 가 비어 있 으 면 이 코드 에 들 어가 지 않 기 때 문 입 니 다.formData 는 post Data 가 비어 있 는 것 을 발견 하면 body 에서 데 이 터 를 가 져 오기 때문에 해결 되 지 않 았 습 니 다.
연구 코드 는 formData 의 데이터 만 바 꿀 수 있 음 을 발견 했다.
                if(null != formData){
                    String param = new String(formData);
                    if(param.contains("%%")){
                        param = param.replace("%%","%25%");
                        formData = param.getBytes();
                        len += 2;
                    }
                }

완벽 한 해결!!
글 의 문 제 를 발견 하면 메 시 지 를 남 겨 주세요.제 가 제일 먼저 대답 하 겠 습 니 다.감사합니다.

좋은 웹페이지 즐겨찾기