作为ResquestBody JSON的一部分,重复键或额外键值是否会导致REST环境中的错误请求?

时间:2017-05-06 07:25:16

标签: json spring rest spring-mvc

我是REST环境的新手,我有一个名为Operations的非常简单的bean,具有以下属性

localForage.getItem("data").then((result) => {
    dataArray = dataArray.concat(result);
    localForage.removeItem("data");
    localForage.setItem("data", dataArray);
  });

所以要创建一个操作bean,请求JSON将是

public class Operations
{
String operationName,
int operationPriority,
boolean isOperationParallel,
boolean expirationPolicy
}

在服务器端将请求JSON映射到Operations bean我已经使用了Spring ResquestBody,默认情况下,它会使用最后一个键值覆盖重复键,例如,如果下面是请求,则'{ "operationName": "NewOperation", "operationPriority": 2, "isOperationParallel": false, "expirationPolicy": 30 }' 将是operationName

NewOperationTwo

现在我的QA告诉我它应该导致'{ "operationName": "NewOperation", "operationName": "NewOperationTwo", "operationPriority": 2, "isOperationParallel": false, "expirationPolicy": 30 }' 作为HTTP状态响应。我还被告知如果像“狗”这样的未知属性:“Barks”,它也应该导致400响应也作为request-body的一部分传递,默认情况下Jackson也会忽略它。

现在我的观点是,我可以通过解析请求并查找重复和未知属性来发送400 BAD_REQUEST,但这是否需要此开销?因为如果它是一个授权,那么Spring默认会返回一个400响应,而不是。

任何人都可以帮助我,因为对于请求正文中的重复和未知密钥,标准REST API响应是什么?如果我不将BAD_REQUEST作为响应抛出会产生什么后果?

2 个答案:

答案 0 :(得分:0)

没有为Json中的重复和未知Key定义标准REST API响应。但是,如果您使用Content-Typeapplication/x-www-form-urlencoded mulitpart/from-data,请求参数名称应该是唯一的。这不适用于JSON。因为无法确定每个应用程序中的json fromat。

因此,orginazation的业务需求决定了应该如何处理这种情况。软件开发人员角色是在应用程序中实现此约束。

因此,如果您的质量保证工程师说400状态应该被送回来重复  和未知的领域。必须这样做

<强>更新

如果JSON请求/响应结构已修复。然后,您可以使用JAXB并将值对象(VO)等模式对象设计为常规POJO来处理传入和传出数据。 使用JAXB将Json绑定到java对象,之后可以使用框架提供的评估功能。如果没有它,它将减少你所付出的巨大努力。如果您正在使用泽西岛,请通过暂停链接获得更多想法

JAXB support in jersey

bean validation support in Jersey

答案 1 :(得分:0)

很抱歉对解决方案的回复很晚,但这就是我的目标,

我为jackson创建了一个自定义的HttpMessageConverter,最初我在MappingJackson2HttpMessageConverter&amp; MappingJacksonHttpMessageConverter 但请阅读Jackson并使用MappingJackson2HttpMessageConverter。

以下是自定义消息转换器,基本上需要覆盖其中的三个方法

read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
                    throws IOException, HttpMessageNotReadableException 

是包含来自请求主体的消息并将其传递给ObjectMapper

的方法
public class CustomMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {

    private static final Logger logger =

    private ObjectMapper objectMapper;

    private boolean prefixJson = false;

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#setPrefixJson(boolean)
     */
    @Override
    public void setPrefixJson(boolean prefixJson) {
        this.prefixJson = prefixJson;
        super.setPrefixJson(prefixJson);
    }


    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#read(java.lang.reflect.Type,
     * java.lang.Class, org.springframework.http.HttpInputMessage)
     */
    @Override
    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
                    throws IOException, HttpMessageNotReadableException {
        objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
        objectMapper.configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, true);
        objectMapper.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true);

        InputStream istream = inputMessage.getBody();
        String responseString = IOUtils.toString(istream);
        try {
            return objectMapper.readValue(responseString, OperatorTokenDefinition.class);
        } catch (UnrecognizedPropertyException ex) {
           throw new YourCustomExceptionClass();
        } catch (InvalidFormatException ex) { 
           throw new YourCustomExceptionClass();
        } catch (IgnoredPropertyException ex) {
            throw new YourCustomExceptionClass();
        } catch (JsonMappingException ex) {
            throw new YourCustomExceptionClass();
        } catch (JsonParseException ex) {
            logger.error("Could not read JSON JsonParseException:{}", ex);
            throw new YourCustomExceptionClass();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#supports(java.lang.Class)
     */
    @Override
    protected boolean supports(Class<?> arg0) {
        return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal(java.lang.Object,
     * org.springframework.http.HttpOutputMessage)
     */
    @Override
    protected void writeInternal(Object arg0, HttpOutputMessage outputMessage)
                    throws IOException, HttpMessageNotWritableException {
        objectMapper = new ObjectMapper();
        String json = this.objectMapper.writeValueAsString(arg0);
        outputMessage.getBody().write(json.getBytes(Charset.defaultCharset()));
    }

    /**
     * @return
     */
    private ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource source = new ResourceBundleMessageSource();
        source.setBasename("messages");
        source.setUseCodeAsDefaultMessage(true);
        return source;
    }
}

现在我们只需要在Spring上下文中注册Custom MessageConverter。在配置类中.Below是代码

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    CustomMappingJackson2HttpMessageConverter jsonConverter =
                    CustomMappingJackson2HttpMessageConverter();
    List<MediaType> mediaTypeList = new ArrayList<MediaType>();
    mediaTypeList.add(MediaType.APPLICATION_JSON);
    jsonConverter.setSupportedMediaTypes(mediaTypeList);
    converters.add(jsonConverter);
    super.configureMessageConverters(converters);
}