平台:Java, Jersey, Jackson
当restful api接收的json数据格式不对的时候,通常我们会返回异常信息,这些信息很有利于定位究竟是哪段json数据出了错。
我们也可以修改返回的信息。由于这些错误信息是框架给出的,所以可以通过重载相应的exception来定制返回的信息。
这么做有什么意义?要求比较严格的情况下,会不想让客户看到具体的信息,比如用到的包的信息(下面的错误信息中就包括包信息);这些信息会被利用,进而分析是用什么实现的,进而利用这种实现潜在的漏洞进行攻击。
这么复杂的东西,对我来说不知道怎么实现,还好,可以参考这里:
http://javareferencegv.blogspot.com/2015/07/handle-invalid-json-request-by.html
我呢,用了一下,没问题;把整个方案记录一下:
假定一个restful pai,对应的输入参数的POJO是:
- class mydata{
- String name;
- String[] days;
- Map price;
- }
正常的输入应该是:
- {"name":"TOM","days":["20161223"],"things":{"apple":"11","orange:"12"}}
但是如果给的json数据是非法的,那么会抛出如下错误:
case 1:
输入:
- {"name":"TOM","days":["20161223"],abcdefg,"things":{"apple":"11","orange:"12"}}
- Unexpected character ('a' (code 97)): was expecting double-quote to start field name at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@7483; line: 1, column: 35]
输入:
- {"name":"TOM","days":"what","things":{"apple":"11","orange:"12"}}
- Can not deserialize instance of java.lang.String[] out of VALUE_STRING token at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@983232; line: 1, column: 22] (through reference chain: xxx.yyy.mydata["days"])
输入:
- {"name":"TOM","days":["20161223"],"things":{"apple"}}
- Unexpected character ('}' (code 125)): was expecting a colon to separate field name and value at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@7632323; line: 1, column: 51] at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@2432432; line: 1, column: 55] (through reference chain: xxx.yyy.mydata["price"])
如果说不想给出这样详细的信息,而只是想提示一下有问题,那么可以通过重载相应的exception来做到。具体修改如下:
"web.xml"
- <servlet>
- <servlet-name>myServlet</servlet-name>
- <servlet-class>
- org.glassfish.jersey.servlet.ServletContainer
- </servlet-class>
- <init-param>
- <param-name>javax.ws.rs.Application</param-name>
- <param-value>xxx.yyy.register</param-value>
- </init-param>
- <init-param>
- <param-name>
- com.sun.jersey.api.json.POJOMappingFeature
- </param-name>
- <param-value>true</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
"xxx.yyy.register.java"
- package xxx.yyy;
- import java.io.File;
- import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
- import org.glassfish.jersey.server.ResourceConfig;
- import com.fasterxml.jackson.annotation.JsonInclude;
- import com.fasterxml.jackson.annotation.JsonInclude.Include;
- import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
- import javax.ws.rs.ext.MessageBodyReader;
- import javax.ws.rs.ext.MessageBodyWriter;
- public class register extends ResourceConfig {
- public register() {
- packages("xxx.yyy");
- register(YourJsonProvider.class);
- register(MyJsonParseExceptionMapper.class);
- register(MyJsonMappingExceptionMapper.class);
- }
- }
"MyJsonParseExceptionMapper.java"
- package xxx.yyy;
- import com.fasterxml.jackson.core.JsonParseException;
- import javax.ws.rs.core.MediaType;
- import javax.ws.rs.core.Response;
- import javax.ws.rs.ext.ExceptionMapper;
- import javax.ws.rs.ext.Provider;
- @Provider
- public class MyJsonParseExceptionMapper implements ExceptionMapper{
- @Override
- public Response toResponse(JsonParseException exception)
- {
- String info = "{\"Error\":\"It is an error, invalid JSON format.\"}";
- return Response
- .status(Response.Status.BAD_REQUEST)
- .entity(info)
- .type( MediaType.APPLICATION_JSON)
- .build();
- }
- }
"MyJsonMappingExceptionMapper.java"
- package xxx.yyy;
- import com.fasterxml.jackson.databind.JsonMappingException;
- import javax.ws.rs.core.MediaType;
- import javax.ws.rs.core.Response;
- import javax.ws.rs.ext.ExceptionMapper;
- import javax.ws.rs.ext.Provider;
- @Provider
- public class MyJsonMappingExceptionMapper implements ExceptionMapper{
- @Override
- public Response toResponse(JsonMappingException exception)
- {
- String info = "{\"Error\":\"JSON format is OK, but some part's type is wrong.\"}";
- return Response
- .status(Response.Status.BAD_REQUEST)
- .entity(info)
- .type( MediaType.TEXT_PLAIN)
- .build();
- }
- }
此时,再执行前面那几个错误的输入,可以得到如下输出:
case 1:
输入:
- {"name":"TOM","days":["20161223"],abcdefg,"things":{"apple":"11","orange:"12"}}
- {"Error":"It is an error, invalid JSON format."}
case 2:
输入:
- {"name":"TOM","days":"what","things":{"apple":"11","orange:"12"}}
- {"Error":"It is an error, invalid JSON format."}
case 3:
输入:
- {"name":"TOM","days":["20161223"],"things":{"apple"}}
- {"Error":"It is an error, invalid JSON format."}
用到的一些jar (其实不需要这么多):
jackson-annotations-2.8.4.jar
jackson-databind-2.8.4.jar
jackson-jaxrs-json-provider-2.8.4.jar
jackson-xc-1.9.2.jar
jackson-core-2.8.4.jar
jackson-jaxrs-1.9.2.jar
jackson-mapper-asl-1.9.2.jar
jackson-core-asl-1.9.2.jar
jackson-jaxrs-base-2.8.4.jar
jackson-module-jaxb-annotations-2.8.4.jar
javax.ws.rs-api-2.0.1.jar
jersey-client-2.25.jar
jersey-container-servlet-core-2.25.jar
jersey-guava-2.25.jar
jersey-media-json-jackson-2.25.jar
jersey-common-2.25.jar
jersey-core-1.19.3.jar
jersey-json-1.19.3.jar
jersey-server-2.25.jar
jersey-container-servlet-2.25.jar
jersey-entity-filtering-2.25.jar
jersey-media-jaxb-2.25.jar
jsr305-3.0.0.jar