HttpServletRequest 获取参数、header、body

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

先上张效果图:

sentry上的效果

如果看不清,请点击图片查看原图,谢谢。

这张图里面有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<String, String[]> 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<String, String> headers = getHeadersInfo(request);
        if (!headers.isEmpty()) {
            eventBuilder.withExtra("headers", headers);
        }
    }

    private static Map<String, String> getHeadersInfo(HttpServletRequest request) {
        Map<String, String> 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);
        }
    }
}

使用的类可能如下:

@ControllerAdvice
public class GlobalExceptionHandler {

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

本文本质上是对 自建 sentry 并与 spring boot 集成  和  spring boot 全局异常拦截 并通过 webhook 发送到 钉钉机器人  的补充。

本博客若无特殊说明则由 full-stack-trip 原创发布
转载请点名出处:全栈之旅 > HttpServletRequest 获取参数、header、body
本文地址:https://www.kpromise.top/httpservletrequest-get-params-body-headers/

发表评论

电子邮件地址不会被公开。 必填项已用*标注