gpt4 book ai didi

java - 无法在 Spring Boot 中拦截和操作 HttpServletResponse

转载 作者:搜寻专家 更新时间:2023-11-01 02:59:29 27 4
gpt4 key购买 nike

我需要对我的 Spring Boot 服务接收到的每个 JSON 请求负载进行 Base64 解码。在使用 HTTP POST 方法发布之前,JSON 负载将在客户端进行 Base64 编码。此外,在呈现给调用客户端应用程序之前,我还需要对 JSON 响应进行 Base64 编码。

我需要使用处理程序拦截器来减少样板代码。我已经通过使用拦截器实现了操作的请求/传入部分,但尚未实现响应部分。我已经在下面发布了代码片段。拦截响应和对其进行 base64 编码的代码位于拦截器类的 postHandle 方法中。

我在这里做错了什么?

拦截器类:

public class Base64ResponseEncodingInterceptor implements HandlerInterceptor {   
private static final String DECODED_REQUEST_ATTRIB = "decodedRequest";
private static final String POST = "POST";


@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView arg3) throws Exception {
try {
if (POST.equalsIgnoreCase(request.getMethod())) {
CharResponseWrapper res = new CharResponseWrapper(response);
res.getWriter();
byte[] encoded = Base64.encodeBase64(res.toString().getBytes());
byte[] encoded = Base64.encodeBase64(response.getHeader(ENCODED_RESPONSE_ATTRIB).getBytes());
response.getWriter().write(new String(encoded));
}
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}


// preHandle and afterCompletion methods
// Omitted
}

上面使用的CharResponseWrapper类:

public class CharResponseWrapper extends HttpServletResponseWrapper {

protected CharArrayWriter charWriter;

protected PrintWriter writer;

protected boolean getOutputStreamCalled;

protected boolean getWriterCalled;


public CharResponseWrapper(HttpServletResponse response) {
super(response);
charWriter = new CharArrayWriter();
}


@Override
public ServletOutputStream getOutputStream() throws IOException {
if (getWriterCalled) {
throw new IllegalStateException("getWriter already called");
}
getOutputStreamCalled = true;
return super.getOutputStream();
}


@Override
public PrintWriter getWriter() throws IOException {
if (writer != null) {
return writer;
}
if (getOutputStreamCalled) {
throw new IllegalStateException("getOutputStream already called");
}
getWriterCalled = true;
writer = new PrintWriter(charWriter);
return writer;
}


@Override
public String toString() {
String s = null;
if (writer != null) {
s = charWriter.toString();
}
return s;
}
}

注册拦截器的JavaConfig类:

@Configuration
@EnableJpaRepositories(repositoryBaseClass = BaseRepositoryBean.class, basePackages = "")
@EntityScan(basePackages = { "com.companyname", "com.companyname.productname"})
public class RestConfig extends WebMvcConfigurerAdapter {


@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new Base64ResponseEncodingInterceptor());
}

}

Controller 类,其中使用了拦截器(此处仅显示工作请求段):

@Autowired
HttpServletRequest request;

String decodedRequest = null;

@ModelAttribute("decodedRequest")
public void getDecodedParam(){
decodedRequest = (String) request.getAttribute("decodedRequest");
}

postHandle 方法中的代码不起作用。 HttpServletResponsenull 或我收到异常消息:

getOutputStream already called

更新:解决直接在 ResponseBodyAdvice 中读取响应的解决方案在 Controller 类中,我添加了以下内容:

@RestController
@RequestMapping("/api/ipmanager")
public class IPProfileRestController extends AbstractRestController {

@Autowired
HttpServletResponse response;

String encodedResponse = null;

@ModelAttribute("encodedResponse")
public void getEncodedResponse(){
response.setHeader("encodedResponse", StringUtils.EMPTY);
}

@RequestMapping(value = "/time", method = { RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE }, consumes = {
MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody String saveAccessClientTime(@RequestBody String ecodedRequest) {

// Some code here

String controllerResponse = prettyJson(iPProfileResponse);
response.setHeader("encodedResponse", controllerResponse);
return controllerResponse;
}
}

我在 ResponseBodyAdvice

中有以下内容
@ControllerAdvice
public class Base64EncodedResponseBodyAdvice implements ResponseBodyAdvice<Object> {

@Override
public boolean supports(MethodParameter returnType,
Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}

@Override
public Object beforeBodyWrite(Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> converterType,
ServerHttpRequest request,
ServerHttpResponse response) {

String body1 = StringUtils.EMPTY;
// Encode the response and return

List<String> listOfHeaderValues = response.getHeaders().get("encodedResponse");

body1=new String(Base64.encodeBase64(listOfHeaderValues.get(0).getBytes()));

return body1;
}

}

最佳答案

作为Spring MVC documentation状态:

the postHandle method of HandlerInterceptor is not always ideally suited for use with @ResponseBody and ResponseEntity methods. In such cases an HttpMessageConverter writes to and commits the response before postHandle is called which makes it impossible to change the response, for example to add a header. Instead an application can implement ResponseBodyAdvice and either declare it as an @ControllerAdvice bean or configure it directly on RequestMappingHandlerAdapter.

话虽这么说:

What am I doing wrong here?

由于响应已经提交,您无法更改它。为了更改响应,您应该注册 ResponseBodyAdvice<T> 并将您的响应编码逻辑放在那里:

@ControllerAdvice
public class Base64EncodedResponseBodyAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType,
Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}

@Override
public Object beforeBodyWrite(Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> converterType,
ServerHttpRequest request,
ServerHttpResponse response) {

// Encode the response and return
}
}

关于java - 无法在 Spring Boot 中拦截和操作 HttpServletResponse,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39963084/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com