java

HttpServletRequest 获取参数、header、body

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

先上张效果图:

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

这张图里面有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

Share
Published by
full-stack-trip

Recent Posts

Android 自定义 View 入门

说来惭愧,工作数年,连基本的自…

4 年 ago

retrofit 同时支持 xml 和 json

retrofit 解析 jso…

4 年 ago

mysql - 存储过程 从入门到放弃

最近有个报表的需求,于是乎用了…

4 年 ago

奶嘴战略 - 你不得不知道的扎心真相(一)

一句:英雄枯骨无人问,戏子家事…

4 年 ago

acme.sh 的简单使用

acme.sh 是纯 shel…

4 年 ago

wrk -更现代化的http压测工具

wrk 是一款更现代化的 ht…

4 年 ago