过滤器中修改响应体后,前端无法正常解析,求教如何处理?

作者站长头像
站长
· 阅读数 11

在过滤器中修改响应体后,前端无法正常解析返回的Json对象。这个过滤器是为了实现把带id的Long字段转换成String再返回给前端。

@Component
@Slf4j
public class LongTypeFilter extends OncePerRequestFilter {
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        log.debug("进入过滤器");

        // 使用 ContentCachingResponseWrapper 包装响应
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);

        // 过滤器链继续
        filterChain.doFilter(request, responseWrapper);

        // 获取原始的响应数据
        byte[] responseBody = responseWrapper.getContentAsByteArray();

        // 获取原始响应的字符编码
        String charset = response.getCharacterEncoding();

        String contentType = response.getContentType();

        // 判断是否需要进行 JSON 数据转换
        if (contentType != null && contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) {
            // 将原始响应数据转换为 JsonNode
            JsonNode rootNode = objectMapper.readTree(new String(responseBody, charset));

            // 判断是否包含 RespResult 对象
            if (rootNode.has("code") && rootNode.has("msg") && rootNode.has("result")) {
                JsonNode resultNode = rootNode.get("result");

                // 判断 result 属性是否为对象,并且包含 Long 类型字段
                    checkAndConvertLongToString(resultNode);
            }
            log.debug(rootNode.toString());
            // 将修改后的数据写回响应
            String modifiedResponse = rootNode.toString();
            //responseWrapper.setContentType(MediaType.APPLICATION_JSON_VALUE + ";charset=" + charset);
            byte[] modifiedBytes = modifiedResponse.getBytes(charset);
            responseWrapper.setContentLength(modifiedBytes.length);
            responseWrapper.getWriter().write(modifiedResponse);
            responseWrapper.copyBodyToResponse();
            log.debug(response.getContentType());
            
        } else {
            // 非 JSON 格式的响应数据,直接写回响应
            responseWrapper.copyBodyToResponse();
        }

    }

    private void checkAndConvertLongToString(JsonNode node) {
        if (node.isArray()) {
            // 如果是数组,遍历数组内的元素
            for (JsonNode arrayElement : node) {
                if (arrayElement.isObject()) {
                    // 如果数组元素是对象,递归调用处理对象
                    checkAndConvertLongToString(arrayElement);
                }
            }
        } else if (node.isObject()) {
            // 如果是对象,继续处理对象内的字段
            Iterator<String> fieldNames = node.fieldNames();
            while (fieldNames.hasNext()) {
                String fieldName = fieldNames.next();
                JsonNode field = node.get(fieldName);

                if (field != null) {
                    if (field.isLong() && field.canConvertToLong() && field.asLong() > Math.pow(2, 53) - 1) {
                        ((ObjectNode) node).putPOJO(fieldName, String.valueOf(field.asLong()));
                    } else if (field.isObject()) {
                        checkAndConvertLongToString(field);
                    }
                }
            }
        }
    }
}

尝试了重新设置ContentType不行,ContentLength应该也没问题吧。前端拿到的返回数据是这样的。

{data: '{"code":200,"msg":"访问成功","result":[{"id":101433906…ice":0.02,"courseSort":3}]}],"time":"2023-12-19"}', status: 200, statusText: '', headers: AxiosHeaders...}
回复
1个回答
avatar
test
2024-06-23

直接使用Jackson2ObjectMapperBuilderCustomizer给Jackson 注册long序列化为string的序列化器不就行了吗,要这么大费周章从response读出来再写回去。

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容