[英]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.