httpservletrequest_HttpServletRequest 获取参数、header、body

  • Post author:
  • Post category:其他


本文的初衷是java后端崩溃后,如何把入参传给 Sentry,从而更快速的定位和解决问题。入参包括:query string、form-data、body,还有 url、headers,当然考虑到分布式部署,还应该拿到当前的服务器 ip 以及端口,至于用户信息,header 里面一般包含了。

先上张效果图:

016e4357ea04d7c8609d9ced7ea55f38.png

这张图里面有body,headers,localAddr、localPort、method、params、remoteHost、url等,可以说足够我们定位那个接口错了(url),用户的入参(params是query string + form data的集合,body 是 post 请求的请求体),当时的服务器 localAddr 以及 运行端口 localPort,另外还有 headers, headers 一般会包含用户的信息,比如 token,如果使用了 网关,那么 headers 可能包含更多信息,比如 用户 id、用户 手机号、等等,具体跟网关有关啦。remoteHost 可能用不着,headers 里面包含了足够多的信息了。

好了,具体相关的 异常上报类如下:

import io.sentry.Sentry;import io.sentry.event.Event;import io.sentry.event.EventBuilder;import io.sentry.event.User;import io.sentry.event.interfaces.ExceptionInterface;import tv.drplay.util.StringUtils;import javax.servlet.http.HttpServletRequest;import java.util.Enumeration;import java.util.HashMap;import java.util.Map;import java.util.stream.Collectors;public class Crash {    public static void onCrash(Exception e, HttpServletRequest request) {        String url = request.getRequestURI();        EventBuilder eventBuilder = new EventBuilder();        eventBuilder.withExtra("url", url);        eventBuilder.withExtra("method", request.getMethod());        addParams(request, eventBuilder);        addHeaders(request, eventBuilder);        addUser(request, eventBuilder);        eventBuilder.withExtra("localPort", request.getLocalPort());        eventBuilder.withExtra("localAddr", request.getLocalAddr());        eventBuilder.withMessage(e.getMessage()).withLevel(Event.Level.ERROR).withSentryInterface(new ExceptionInterface(e));        Sentry.capture(eventBuilder);    }    private static void addParams(HttpServletRequest request, EventBuilder eventBuilder) {        Map map = request.getParameterMap();        if (map != null && !map.isEmpty()) {            eventBuilder.withExtra("params", map);        }        try {            String body = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));            if (!StringUtils.isBlank(body)) {                eventBuilder.withExtra("body", body);            }        } catch (Exception ignore) {        }    }    private static void addHeaders(HttpServletRequest request, EventBuilder eventBuilder) {        Map headers = getHeadersInfo(request);        if (!headers.isEmpty()) {            eventBuilder.withExtra("headers", headers);        }    }    private static Map getHeadersInfo(HttpServletRequest request) {        Map map = new HashMap<>();        try {            Enumeration headerNames = request.getHeaderNames();            if (headerNames == null) return map;            while (headerNames.hasMoreElements()) {                String key = (String) headerNames.nextElement();                String value = request.getHeader(key);                map.put(key, value);            }            return map;        } catch (Exception ignore) {        }        return map;    }    private static void addUser(HttpServletRequest request, EventBuilder eventBuilder) {        String host = request.getRemoteHost();        if (!StringUtils.isBlank(host)) {//            User user = new User(null, null, host, null);//            Sentry.getContext().setUser(user);            eventBuilder.withExtra("remoteHost", host);        }    }}

使用的类可能如下:

@ControllerAdvicepublic class GlobalExceptionHandler {    @ExceptionHandler(CustomException.class)    @ResponseBody    Response handleCustomException(CustomException customException) {        customException.printStackTrace();        return customException.getError();    }}