Spring 引导替换 Filter 中的 ServletException 响应
Spring Boot replace ServletException response in Filter
我有一个 Spring 引导过滤器,我正在使用它来使用 Jwt
进行身份验证。如果成功,一切都会很好,我会发出 Json
对我的设计的回应。但是,如果 Authorization
header 丢失或不正确,我会抛出带有自定义消息的 ServletException
。这会导致丑陋的 Json
看起来像这样:
{
"timestamp":1453192910756,
"status":500,
"error":"Internal Server Error",
"exception":"javax.servlet.ServletException",
"message":"Invalid Authorization header.",
"path":"/api/test"
}
我希望自定义此 Json
,使其采用我用于所有其他回复的标准格式。
我的过滤器代码在这里:
public class JwtFilter extends GenericFilterBean {
@Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
System.out.println("JwtFilter");
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null) {
throw new ServletException("Missing Authorization header.");
}
if (!authHeader.startsWith("Bearer ")) {
throw new ServletException("Invalid Authorization header.");
}
final String token = authHeader.substring(7);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (final SignatureException e) {
throw new ServletException("Invalid token.");
}
chain.doFilter(req, res);
}
}
我尝试使用包装器来包装响应,但这没有用。另一个 SO post 说响应是不可更改的,但这甚至没有意义。
我认为正确的方法是编辑 ServletResponse
res
但我无法让它工作。
谢谢!
编辑: 有点老套,但确实有效。如果有更好的方法,请回答:
public class JwtFilter extends GenericFilterBean {
@Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
System.out.println("JwtFilter");
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Missing Authorization header."));
return;
}
if (!authHeader.startsWith("Bearer ")) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Invalid Authorization header."));
return;
}
final String token = authHeader.substring(7);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (Exception f) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Invalid token."));
return;
}
chain.doFilter(req, res);
}
}
一般来说,包装响应然后在调用doFilter
之后修改响应输出流是正确的做法,例如
PrintWriter out = response.getWriter();
CharResponseWrapper wrapper = new CharResponseWrapper(
(HttpServletResponse)response);
chain.doFilter(request, wrapper);
CharArrayWriter caw = new CharArrayWriter();
caw.write("your json");
response.setContentLength(caw.toString().getBytes().length);
out.write(caw.toString());
out.close();
然而,您的用例似乎更适合在 RestController 处理程序方法中处理,可能与 @ExceptionHandler(ServletException.class) 注释方法结合使用。这将是一种更通用的方法,允许您利用 Spring 内容协商的力量来处理 JSON 序列化。
我有一个 Spring 引导过滤器,我正在使用它来使用 Jwt
进行身份验证。如果成功,一切都会很好,我会发出 Json
对我的设计的回应。但是,如果 Authorization
header 丢失或不正确,我会抛出带有自定义消息的 ServletException
。这会导致丑陋的 Json
看起来像这样:
{
"timestamp":1453192910756,
"status":500,
"error":"Internal Server Error",
"exception":"javax.servlet.ServletException",
"message":"Invalid Authorization header.",
"path":"/api/test"
}
我希望自定义此 Json
,使其采用我用于所有其他回复的标准格式。
我的过滤器代码在这里:
public class JwtFilter extends GenericFilterBean {
@Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
System.out.println("JwtFilter");
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null) {
throw new ServletException("Missing Authorization header.");
}
if (!authHeader.startsWith("Bearer ")) {
throw new ServletException("Invalid Authorization header.");
}
final String token = authHeader.substring(7);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (final SignatureException e) {
throw new ServletException("Invalid token.");
}
chain.doFilter(req, res);
}
}
我尝试使用包装器来包装响应,但这没有用。另一个 SO post 说响应是不可更改的,但这甚至没有意义。
我认为正确的方法是编辑 ServletResponse
res
但我无法让它工作。
谢谢!
编辑: 有点老套,但确实有效。如果有更好的方法,请回答:
public class JwtFilter extends GenericFilterBean {
@Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
System.out.println("JwtFilter");
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Missing Authorization header."));
return;
}
if (!authHeader.startsWith("Bearer ")) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Invalid Authorization header."));
return;
}
final String token = authHeader.substring(7);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (Exception f) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Invalid token."));
return;
}
chain.doFilter(req, res);
}
}
一般来说,包装响应然后在调用doFilter
之后修改响应输出流是正确的做法,例如
PrintWriter out = response.getWriter();
CharResponseWrapper wrapper = new CharResponseWrapper(
(HttpServletResponse)response);
chain.doFilter(request, wrapper);
CharArrayWriter caw = new CharArrayWriter();
caw.write("your json");
response.setContentLength(caw.toString().getBytes().length);
out.write(caw.toString());
out.close();
然而,您的用例似乎更适合在 RestController 处理程序方法中处理,可能与 @ExceptionHandler(ServletException.class) 注释方法结合使用。这将是一种更通用的方法,允许您利用 Spring 内容协商的力量来处理 JSON 序列化。