[英]How to check if unsupported parameter is contained in REST request?
Spring(引导)是否有一种方法来检查 REST 请求是否包含被调用的 REST 方法未明确声明的参数?
使用required标志,我们可以强制客户端在请求中包含某个参数。 我正在寻找一种类似的方法来禁止客户端发送控制器方法声明中未明确提及的参数:
@RequestMapping("/hello")
public String hello(@RequestParam(value = "name") String name) {
//throw an exception if a REST client calls this method and
// sends a parameter with a name other than "name"
//otherwise run this method's logic
}
例如调用
curl "localhost:8080/hello?name=world&city=London"
应该导致4xx答案。
一种选择是显式检查意外参数:
@RequestMapping("/hello")
public String hello(@RequestParam Map<String,String> allRequestParams) {
//throw an exception if allRequestParams contains a key that we cannot process here
//otherwise run this method's logic
}
但是,是否也可以在保持与第一个示例相同的@RequestParam
使用方便的同时获得相同的结果?
编辑:对不起,我没有看到与这个问题有任何联系。 另一个问题是关于运行时的注解处理。 我的问题是关于 Spring 的 REST 引擎的行为。 我错过了什么吗?
@Component
public class TooManyParamatersHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod m = (HandlerMethod) handler;
if (m.getMethod().getName().equals("error")) {
return true;
}
List<String> allowedParameters = Stream.of(m.getMethodParameters())
.flatMap(p -> Stream.of(p.getParameterAnnotation(RequestParam.class)))
.filter(Objects::nonNull)
.map(RequestParam::name).collect(Collectors.toList());
ArrayList<String> actualParameters = Collections.list(request.getParameterNames());
actualParameters.removeAll(allowedParameters);
if (!actualParameters.isEmpty()) {
throw new org.springframework.web.bind.ServletRequestBindingException(
"unexpected parameter: " + actualParameters);
}
return true;
}
}
您可以通过从 JavaEE 7 添加的ContainerRequestFilter
特性来实现,它允许您访问与当前请求匹配的资源类和资源方法,并让您在没有匹配时执行您想要的操作。
你可以在这里阅读更多:
https://docs.oracle.com/javaee/7/api/javax/ws/rs/container/ResourceInfo.html
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.QueryParam;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.Provider;
@Provider
public class RequestParamFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
Set<String> acceptedParamList = new HashSet<String>();
Method method = resourceInfo.getResourceMethod();
for (Annotation[] annos : method.getParameterAnnotations()) {
for (Annotation anno : annos) {
if (anno instanceof QueryParam) {
acceptedParamList.add(((QueryParam) anno).value());
}
}
}
MultivaluedMap<String, String> queryParams = requestContext.getUriInfo().getQueryParameters();
for (String param : queryParams .keySet()) {
if (!acceptedParamList.contains(param)) {
requestContext.abortWith(Response.status(Status.BAD_REQUEST).entity("Unexpected paramter found : "+param).build());
}
}
}
}
PN:大多数情况下,过滤器会影响您的应用程序速度,特别是如果您有复杂的链!
我建议在这种情况(和类似情况)中使用它,因为大多数请求根本不应该到达服务器应用程序。
我希望这对你有帮助,祝你编码愉快! =)
在这种情况下,您需要HandlerInterceptor
或HandlerInterceptorAdapter
,覆盖preHandle
方法
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//request param validation validation
return true; //or throw exception
}
ServletRequest.getParameterMap() 返回请求参数的键值映射。
据我所知,您不能简单地禁止使用 Spring 的参数。 老实说,这个问题相当值得怀疑和不必要,我认为这是一个反模式。
但是,Spring 为每个映射提供了HttpServletRequest
和HttpServletResponse
对象到控制器方法签名。 使用HttpServletRequest::getParameterMap
接收传递参数的 Map 以进行进一步的迭代和验证。
@RequestMapping("/hello")
public String hello(RequestParam(value = "name") String name, HttpServletRequest request, HttpServletResponse response) {
final Map<String, String[]> parameterMap = request.getParameterMap();
// logics
}
将这些对象仅传递给@RequestMapping("/hello")
允许仅对选定的映射执行验证。 如果您想全局定义此行为,我建议您使用HandlerInterceptor::preHandle
作为此处的回答。
如果你让hello
参数required=true
,那么你可以只检查 Map 的大小是否等于1
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.