curl 请求日志_SpringBoot 记录HTTP请求日志,curl格式,可直接运行于bash,也可导入postman...

此博客展示了LoggableDispatcherServlet类的代码,该类继承自DispatcherServlet,用于记录HTTP请求和响应的详细信息,包括请求方法、URL、头部信息、请求体和响应体等,并将这些信息以JSON格式记录日志,同时生成curl请求命令,方便调试和分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

packagecom.hsh.common.dispatch;importcn.hutool.core.collection.CollectionUtil;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.node.ObjectNode;importorg.apache.commons.compress.utils.IOUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.core.Ordered;importorg.springframework.core.annotation.Order;importorg.springframework.http.HttpStatus;importorg.springframework.util.CollectionUtils;importorg.springframework.util.ObjectUtils;importorg.springframework.util.StringUtils;importorg.springframework.web.servlet.DispatcherServlet;importorg.springframework.web.servlet.HandlerExecutionChain;importorg.springframework.web.util.ContentCachingRequestWrapper;importorg.springframework.web.util.ContentCachingResponseWrapper;importjavax.servlet.ReadListener;importjavax.servlet.ServletInputStream;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletRequestWrapper;importjavax.servlet.http.HttpServletResponse;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.IOException;importjava.io.PrintWriter;importjava.text.MessageFormat;import java.util.*;

@Order(Ordered.HIGHEST_PRECEDENCE)//最高优先级 方便拦截404什么的

public class LoggableDispatcherServlet extendsDispatcherServlet {private static final Logger logger = LoggerFactory.getLogger("HttpLogger");private static final ObjectMapper mapper = newObjectMapper();private static final long serialVersionUID = -2151909516770706554L;

@Overrideprotected void doDispatch(HttpServletRequest request, HttpServletResponse response) throwsException {//if ("GET".equals(request.getMethod())) {//super.doDispatch(request, response);//return;//}

List curlItemList = new ArrayList<>();

ContentCachingResponseWrapper responseWrapper= newContentCachingResponseWrapper(response);

setThrowExceptionIfNoHandlerFound(true);

ObjectNode rootNode=mapper.createObjectNode();

ObjectNode reqNode=mapper.createObjectNode();

ObjectNode resNode=mapper.createObjectNode();

String method=request.getMethod();

curlItemList.add(MessageFormat.format("-X ''{0}''", method));

rootNode.put("method", method);

String requestUrl=request.getRequestURL().toString();

rootNode.put("url", requestUrl);

rootNode.put("remoteAddr", request.getRemoteAddr());

rootNode.put("x-forwarded-for", request.getHeader("x-forwarded-for"));

rootNode.set("request", reqNode);

rootNode.set("response", resNode);

reqNode.set("headers", mapper.valueToTree(getRequestHeaders(request)));try{

reqNode.set("query", mapper.valueToTree(request.getParameterMap()));if ("GET".equals(method)) {

StringBuilder stringBuilder= newStringBuilder();

stringBuilder.append("'").append(requestUrl);

Enumeration parameterNames =request.getParameterNames();if(parameterNames.hasMoreElements()) {

stringBuilder.append("?");

}while(parameterNames.hasMoreElements()) {

String name=parameterNames.nextElement();

String[] values=request.getParameterValues(name);for(String value : values) {

stringBuilder.append(name).append("=").append(value).append("&");

}

}

stringBuilder.append("'");

String url=stringBuilder.toString();if (url.endsWith("&'")) {

url= url.substring(0, url.length() - 2) + "'";

}

curlItemList.add(url);super.doDispatch(request, responseWrapper);

}else{

curlItemList.add("'" + requestUrl + "'");if(isFormPost(request)) {

ContentCachingRequestWrapper bufferedServletRequestWrapper= newContentCachingRequestWrapper(request);

reqNode.set("body", mapper.valueToTree(request.getParameterMap()));

reqNode.put("bodyIsJson", false);

StringBuilder stringBuilder= newStringBuilder();

Enumeration parameterNames =request.getParameterNames();while(parameterNames.hasMoreElements()) {

String name=parameterNames.nextElement();

String[] values=request.getParameterValues(name);for(String value : values) {

stringBuilder.append(name).append("=").append(value).append("&");

}

}

String paramsStr=stringBuilder.toString();if (paramsStr.endsWith("&")) {

paramsStr= paramsStr.substring(0, paramsStr.length() - 1);

}

curlItemList.add(MessageFormat.format("--data-raw ''{0}''", paramsStr));super.doDispatch(bufferedServletRequestWrapper, responseWrapper);

}else if(isJsonPost(request)) {

BufferedServletRequestWrapper bufferedServletRequestWrapper= newBufferedServletRequestWrapper(request);

ServletInputStream inputStream=bufferedServletRequestWrapper.getInputStream();byte[] contentAsByteArray =IOUtils.toByteArray(inputStream);

reqNode.set("body", mapper.readTree(contentAsByteArray));

reqNode.put("bodyIsJson", true);

curlItemList.add(MessageFormat.format("--data-binary ''{0}''", mapper.readTree(contentAsByteArray)));super.doDispatch(bufferedServletRequestWrapper, responseWrapper);

}else if (isTextPost(request) ||isXmlPost(request)) {

BufferedServletRequestWrapper bufferedServletRequestWrapper= newBufferedServletRequestWrapper(request);

ServletInputStream inputStream=bufferedServletRequestWrapper.getInputStream();byte[] contentAsByteArray =IOUtils.toByteArray(inputStream);

reqNode.put("body", newString(contentAsByteArray));

reqNode.put("bodyIsJson", false);

curlItemList.add(MessageFormat.format("--data-binary ''{0}''", newString(contentAsByteArray)));super.doDispatch(bufferedServletRequestWrapper, responseWrapper);

}else if(isMediaPost(request)) {

reqNode.put("body", "Media Request Body ContentLength = " +request.getContentLengthLong());

reqNode.put("bodyIsJson", false);super.doDispatch(request, responseWrapper);

}else{

reqNode.put("body", "Unknown Request Body ContentLength = " +request.getContentLengthLong());

reqNode.put("bodyIsJson", false);super.doDispatch(request, responseWrapper);

}

}

HandlerExecutionChain handlerExecutionChain=getHandler(request);if (handlerExecutionChain == null) {//手动判断是不是404 不走系统流程 直接处理 因为会重定向/error

resNode.put("status", HttpStatus.NOT_FOUND.value());

logger.info(rootNode.toString());

response.setStatus(HttpStatus.NOT_FOUND.value());

PrintWriter writer=response.getWriter();

writer.write("Request path not found");

writer.flush();

writer.close();return;

}

System.out.println(handlerExecutionChain);

}finally{byte[] responseWrapperContentAsByteArray =responseWrapper.getContentAsByteArray();

responseWrapper.copyBodyToResponse();//这里有顺序 必须先读body 然后再调用这个方法 才能继续读

resNode.put("status", response.getStatus());

Map responseHeaders =getResponseHeaders(response);//这里判断错误拦截是不是吧url改成error了 如果是就做一下替换 替换的值是错误拦截器写到header里面的

String url = rootNode.get("url").asText();if (url.endsWith("/error")) {

String path= (String) responseHeaders.get("x-error-path");if (!ObjectUtils.isEmpty(path)) {

rootNode.put("url", url.replace("/error", path));

}

}

resNode.set("headers", mapper.valueToTree(responseHeaders));if (isProtoBufPost(responseWrapper) || "GET".equals(request.getMethod())) {

}else{try{

resNode.set("body", mapper.readTree(responseWrapperContentAsByteArray));

resNode.put("bodyIsJson", true);

}catch(Exception e) {

resNode.put("body", newString(responseWrapperContentAsByteArray));

resNode.put("bodyIsJson", false);

}

}

logger.info(rootNode.toPrettyString());

getCurlRequestHeaders(request, curlItemList);

logger.info("curl " + CollectionUtil.join(curlItemList, "\n "));

}

}private MapgetRequestHeaders(HttpServletRequest request) {

Map headers = new HashMap<>();

Enumeration headerNames =request.getHeaderNames();while(headerNames.hasMoreElements()) {

String headerName=headerNames.nextElement();

headers.put(headerName, request.getHeader(headerName));

}returnheaders;

}private void getCurlRequestHeaders(HttpServletRequest request, Listlist) {

Enumeration headerNames =request.getHeaderNames();while(headerNames.hasMoreElements()) {

String headerName=headerNames.nextElement();

String headerValue=request.getHeader(headerName);if (!headerValue.contains("multipart/form-data")) {

list.add(MessageFormat.format("-H ''{0}: {1}''", headerName, headerValue));

}

}

}private MapgetResponseHeaders(HttpServletResponse response) {

Map headers = new HashMap<>();

Collection headerNames =response.getHeaderNames();for(String headerName : headerNames) {

headers.put(headerName, response.getHeader(headerName));

}returnheaders;

}private booleanisFormPost(HttpServletRequest request) {

String contentType=request.getContentType();return (contentType != null && contentType.contains("x-www-form"));

}private booleanisMediaPost(HttpServletRequest request) {

String contentType=request.getContentType();if (contentType != null) {return contentType.contains("stream") || contentType.contains("image") || contentType.contains("video") || contentType.contains("audio");

}return false;

}private booleanisTextPost(HttpServletRequest request) {

String contentType=request.getContentType();if (contentType != null) {return contentType.contains("text/plain") || contentType.contains("text/xml") || contentType.contains("text/html");

}return false;

}private booleanisJsonPost(HttpServletRequest request) {

String contentType=request.getContentType();if (contentType != null) {return contentType.contains("application/json");

}return false;

}private booleanisXmlPost(HttpServletRequest request) {

String contentType=request.getContentType();if (contentType != null) {return contentType.contains("application/xml");

}return false;

}private booleanisProtoBufPost(HttpServletRequest request) {

String contentType=request.getContentType();if (contentType != null) {return contentType.contains("application") && contentType.contains("protobuf");

}return false;

}private booleanisProtoBufPost(HttpServletResponse response) {

String contentType=response.getContentType();if (contentType != null) {return contentType.contains("application") && contentType.contains("protobuf");

}return false;

}private booleanisMultipartFormDataPost(HttpServletRequest request) {

String contentType=request.getContentType();if (contentType != null) {return contentType.contains("multipart/form-data");

}return false;

}class BufferedServletInputStream extendsServletInputStream {privateByteArrayInputStream inputStream;privateServletInputStream is;public BufferedServletInputStream(byte[] buffer, ServletInputStream is) {this.is =is;this.inputStream = newByteArrayInputStream(buffer);

}

@Overridepublic intavailable() {returninputStream.available();

}

@Overridepublic intread() {returninputStream.read();

}

@Overridepublic int read(byte[] b, int off, intlen) {returninputStream.read(b, off, len);

}

@Overridepublic booleanisFinished() {returnis.isFinished();

}

@Overridepublic booleanisReady() {returnis.isReady();

}

@Overridepublic voidsetReadListener(ReadListener listener) {

is.setReadListener(listener);

}

}class BufferedServletRequestWrapper extendsHttpServletRequestWrapper {private byte[] buffer;privateServletInputStream is;public BufferedServletRequestWrapper(HttpServletRequest request) throwsIOException {super(request);this.is =request.getInputStream();

ByteArrayOutputStream byteArrayOutputStream= newByteArrayOutputStream();

byteArrayOutputStream.write(IOUtils.toByteArray(is));this.buffer =byteArrayOutputStream.toByteArray();

}

@OverridepublicServletInputStream getInputStream() {return new BufferedServletInputStream(this.buffer, this.is);

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值