request.getInputStream이 비어 있는 개선 방법

6149 단어
최근 회사의 작은 프로젝트 중 하나가 모듈 최적화를 진행하는데 수요는 각 IP가 요청한 원본 데이터와 응답 데이터를 추적하여 기록하는 것이다.원본 데이터에 RequestBody가 포함되어 있을 때 HttpServletRequest에서 RequestBody를 가져오면 다음과 같은 코드를 사용합니다.
@RequestMapping(value = "/{user}/welcome", method = RequestMethod.POST)
public ModelAndView queryUpdateStatus(@PathVariable String user,
			HttpServletRequest request) throws IOException{
    Map json =new HashMap();
    int size = request.getContentLength();
    InputStream is = request.getInputStream();
    byte[] reqBodyBytes = StreamUtils.readBytes(is, size);
    String res = new String(reqBodyBytes);
    System.out.println("requestBody:"+res);
    
    return new ModelAndView(new JsonView(),json);    
}

물론 더 빠른 방법도 있다. 바로 JAR 패키지 apktool을 도입하는 것이다.jar, 다음 코드를 사용해도 RequestBody를 얻을 수 있습니다.
@RequestMapping(value = "/{user}/welcome", method = RequestMethod.POST)
public ModelAndView queryUpdateStatus(@PathVariable String user,
			HttpServletRequest request) throws IOException{
    Map json =new HashMap();
    String res = IOUtils.toString(request.getInputStream(),"UTF-8");
    System.out.println("requestBody:"+res);
    
    return new ModelAndView(new JsonView(),json);    
}

이제 추적 로깅 요구 사항을 충족하기 위해 모든 디렉터에 AOP 차단을 수행합니다.
@Component
@Aspect
public class LogAspect {

	protected final Logger log = Logger.getLogger(getClass());

	@Around("execution(* demo.web.controller..*.*(..))")
	public Object around(ProceedingJoinPoint jp) throws Throwable {
		String businessName = jp.getSignature().getName();
		String fileName = jp.getSignature().getDeclaringTypeName();
		String params = initAssist(jp);
		int lastIndex = fileName.lastIndexOf(".");
		int cIndex = fileName.lastIndexOf("Controller");
		fileName = fileName.substring(lastIndex + 1, cIndex);
		String requestLog = "actionLog_request:fileName:" + fileName + "...businessName:" + businessName
				+ "...params " + params;
		log.info(requestLog);
		
		Object returnValue = null;
		try {
			returnValue = jp.proceed(jp.getArgs());

			if (returnValue != null) {
				if (returnValue instanceof ModelAndView) {
					JSONObject jsonObj = JSONObject
							.fromObject(((ModelAndView) returnValue).getModel());
					log.info(requestLog+"||actionLog_return:" + jsonObj.toString());
				}
			} else {
				log.info("return:null");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			log.info("abc log err");
			e.printStackTrace();
			String message = e.getMessage();
//			throw e;
		}
		return returnValue;
	}

	

	private String initAssist(JoinPoint jp) {
		String result = "";
		Class clazz = jp.getTarget().getClass();
		String method = jp.getSignature().getName();
		ClassPool pool = ClassPool.getDefault();
		pool.insertClassPath(new ClassClassPath(this.getClass()));
		CtClass cc;
		try {
			cc = pool.get(clazz.getName());
			CtMethod cm = cc.getDeclaredMethod(method);
			Object[] args = jp.getArgs();//     ,       
			String[] paramNames = matchParam(cm, cm.getParameterTypes().length);
			for (int i = 0; i " + args[i].toString() + ",";
						}
						if(args[i] instanceof HttpServletRequest){
							
							HttpServletRequest req = (HttpServletRequest)args[i];
							//  requestHeader
							Map requestHeader = new HashMap();
							Enumeration headerNames = req.getHeaderNames();
							while (headerNames.hasMoreElements()) {
								String key = (String) headerNames
										.nextElement();
								String value = req.getHeader(key);
								requestHeader.put(key, value);
							}
							//  requestBody
							String requestBody=IOUtils.toString(req.getInputStream());
							//  requestParameter
					        Map requestParams = new HashMap();
							Enumeration pNames = req.getParameterNames();
							while (pNames.hasMoreElements()) {
								String key = (String) pNames
										.nextElement();
								String value = req.getHeader(key);
								requestParams.put(key, value);
							}	
						}
					} catch (Exception e) {
						e.printStackTrace();
						
					}
				}else{
					result += paramNames[i] + "-->" + null + ",";
				}
			}

		} catch (NotFoundException e) {
			log.error(clazz.getName(), e);
		}
		return result;
	}

	private String[] matchParam(CtMethod cm, Integer arrLength) {
		try {
			String[] paramNames = new String[arrLength];
			MethodInfo methodInfo = cm.getMethodInfo();
			CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
			LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
					.getAttribute(LocalVariableAttribute.tag);//       
			if (attr == null) {
				log.error("");
				return null;
			}

			for (int i = 0, j = 0; i 

이 때 서비스를 시작하고 인터페이스 디버깅을 요청할 때 다음과 같은 상황을 발견할 수 있습니다.
[demo.web.filter.LogAspect] - requestBody:abc=abc
[demo.web.controller.DemoController] - requestBody:
결론: 두 번째 리퀘스트 사용.getInputStream () 은 정보를 얻을 수 없습니다.
요구 사항을 충족하기 위해 springmvc의 설명 @RequestBody를 사용했으며 컨트롤러 코드는 다음과 같이 수정되었습니다.
@RequestMapping(value = "/{user}/welcome", method = RequestMethod.POST)
public ModelAndView queryUpdateStatus(@PathVariable String user,
			HttpServletRequest request,@RequestBody String requestBodyString) throws IOException{
    Map json =new HashMap();
    System.out.println("requestBody:"+requestBodyString);
    
    return new ModelAndView(new JsonView(),json);    
}

인터페이스 디버깅을 요청할 때 다음과 같은 상황을 발견할 수 있도록 서비스를 시작합니다.
[demo.web.filter.LogAspect] - requestBody:
[demo.web.controller.DemoController] - requestBody:abc=abc
결론:springmvc는 리퀘스트의 입력 흐름을 대응하는 데이터로 전환했기 때문에 입력 흐름은springmvc가 읽었기 때문에 프로그램의 두 번째 읽기 흐름은 반드시 비어 있습니다.
이제 로그 차단기 차단 리퀘스트 바디의 코드 부분을 차단 리퀘스트 바디 스트링으로 바꾸면 됩니다.
처음으로 박문을 썼는데 잘 못 쓴 점이 있어서 양해해 주십시오.
전재 대상:https://blog.51cto.com/13177258/1952881

좋은 웹페이지 즐겨찾기