Java 在控制器之前过滤输入 XML
Java filter input XML before controller
我想验证通过 http POST 请求收到的 XML 对我的 Spring MVC 控制器的请求,但我需要将其验证为 ServletFilter。
在输入流上使用 DocumentBuilderFactory 没问题:我在我的 ServletFilter 中正确解析和分析了输入。
通过我的过滤器,调试器不让我看到它在各种库和 类 中发生了什么,但我无法登陆 Spring 控制器,我直接得到“400 Bad请求”作为响应。
没有这行代码(并且没有xml文件的所有后续解析和验证)在我的过滤器中 :
Document doc = builder.parse(xml);
请求毫无问题地到达 Spring 控制器,控制器将输入 XML 映射到名为 RequestModel.java[=15 的对象=]
但是当我在过滤器中添加解析和验证时,导航会在登陆控制器之前阻塞,而不会抛出任何异常。
这是让我在过滤器中调用失败的片段:
InputStream xml = request.getInputStream();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(xml); //ADDING THIS LINE IT FAILS!
//method continues with xml parsing and validation...
这是我的控制器方法的开始(经过解析,之前导航被阻塞):
@Controller
@EnableSwagger2
@RequestMapping("/listaprocessi")
@Api(description = "Lista processi ammessi", tags="Lista processi")
public class ListaProcessiController {
@RequestMapping(produces = MediaType.APPLICATION_XML_VALUE, consumes = MediaType.APPLICATION_XML_VALUE, method = RequestMethod.POST)
@ResponseBody
@ApiOperation(value="Lista processi")
public BusinessListaProcessiModel listaProcessi(@RequestBody RequestModel requestModel) throws RemoteException{ ...}
是否因为要分析输入,过滤器必须等到流关闭?你有什么建议吗?
您只能处理一次 ServletInputStream。因此,当您在过滤器中处理它时,它无法被控制器的 Spring MVC 框架处理。
我遇到过很多次了。为了解决这个问题,我将 HttpServletRequest 包装在一个新的 class(见下文)中,以允许重新读取 InputStream。如果您将 HttpServletRequest 包装在下面 class 的一个实例中并在您的 DocumentBuilder 中使用它并将其传递给您的 Filter 的 doFilter 方法,那么您应该很好。
public class CachingRequestWrapper extends HttpServletRequestWrapper {
private final String cachedMsgBody;
public CachingRequestWrapper(HttpServletRequest request) throws HttpErrorException {
super(request);
cachedMsgBody = ServletUtils.extractMsgBodyToString(request);
}
public CachingRequestWrapper(HttpServletRequest request, String msgBody) throws HttpErrorException {
super(request);
cachedMsgBody = msgBody;
}
public String getCachedMsgBody() {
return cachedMsgBody;
}
@Override
public BufferedReader getReader() throws IOException {
InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(cachedMsgBody.getBytes()));
return new BufferedReader(isr);
}
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream sis = new ServletInputStream() {
private int i = 0;
byte[] msgBodyBytes = cachedMsgBody.getBytes();
@Override
public int read() throws IOException {
byte b;
if (msgBodyBytes.length > i) {
b = msgBodyBytes[i++];
} else {
b = -1;
}
return b;
}
public boolean isFinished() {
return i == msgBodyBytes.length;
}
public boolean isReady() {
return true;
}
public void setReadListener(ReadListener rl) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
};
return sis;
}
}
参考:
我想验证通过 http POST 请求收到的 XML 对我的 Spring MVC 控制器的请求,但我需要将其验证为 ServletFilter。
在输入流上使用 DocumentBuilderFactory 没问题:我在我的 ServletFilter 中正确解析和分析了输入。
通过我的过滤器,调试器不让我看到它在各种库和 类 中发生了什么,但我无法登陆 Spring 控制器,我直接得到“400 Bad请求”作为响应。
没有这行代码(并且没有xml文件的所有后续解析和验证)在我的过滤器中 :
Document doc = builder.parse(xml);
请求毫无问题地到达 Spring 控制器,控制器将输入 XML 映射到名为 RequestModel.java[=15 的对象=]
但是当我在过滤器中添加解析和验证时,导航会在登陆控制器之前阻塞,而不会抛出任何异常。
这是让我在过滤器中调用失败的片段:
InputStream xml = request.getInputStream();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(xml); //ADDING THIS LINE IT FAILS!
//method continues with xml parsing and validation...
这是我的控制器方法的开始(经过解析,之前导航被阻塞):
@Controller
@EnableSwagger2
@RequestMapping("/listaprocessi")
@Api(description = "Lista processi ammessi", tags="Lista processi")
public class ListaProcessiController {
@RequestMapping(produces = MediaType.APPLICATION_XML_VALUE, consumes = MediaType.APPLICATION_XML_VALUE, method = RequestMethod.POST)
@ResponseBody
@ApiOperation(value="Lista processi")
public BusinessListaProcessiModel listaProcessi(@RequestBody RequestModel requestModel) throws RemoteException{ ...}
是否因为要分析输入,过滤器必须等到流关闭?你有什么建议吗?
您只能处理一次 ServletInputStream。因此,当您在过滤器中处理它时,它无法被控制器的 Spring MVC 框架处理。
我遇到过很多次了。为了解决这个问题,我将 HttpServletRequest 包装在一个新的 class(见下文)中,以允许重新读取 InputStream。如果您将 HttpServletRequest 包装在下面 class 的一个实例中并在您的 DocumentBuilder 中使用它并将其传递给您的 Filter 的 doFilter 方法,那么您应该很好。
public class CachingRequestWrapper extends HttpServletRequestWrapper {
private final String cachedMsgBody;
public CachingRequestWrapper(HttpServletRequest request) throws HttpErrorException {
super(request);
cachedMsgBody = ServletUtils.extractMsgBodyToString(request);
}
public CachingRequestWrapper(HttpServletRequest request, String msgBody) throws HttpErrorException {
super(request);
cachedMsgBody = msgBody;
}
public String getCachedMsgBody() {
return cachedMsgBody;
}
@Override
public BufferedReader getReader() throws IOException {
InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(cachedMsgBody.getBytes()));
return new BufferedReader(isr);
}
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream sis = new ServletInputStream() {
private int i = 0;
byte[] msgBodyBytes = cachedMsgBody.getBytes();
@Override
public int read() throws IOException {
byte b;
if (msgBodyBytes.length > i) {
b = msgBodyBytes[i++];
} else {
b = -1;
}
return b;
}
public boolean isFinished() {
return i == msgBodyBytes.length;
}
public boolean isReady() {
return true;
}
public void setReadListener(ReadListener rl) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
};
return sis;
}
}
参考: