问题描述:
今天在Springboot框架中使用Filter遇到了这个问题。具体代码如下
import com.alibaba.fastjson.JSONObject;
import com.aust.tlaiswebmanagement.pojo.Result;
import com.aust.tlaiswebmanagement.utils.JWTUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @autehor zi
* @date 11/8/2023
* @Description
*/
@Slf4j
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
@Autowired
private JWTUtils jwtUtils;
@Override
//拦截到请求时,调用该方法,可调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
Integer id=null;
String name=null;
String username=null;
//强转请求类型
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//1.获取请求url
String url = req.getRequestURL().toString();
//2.判断请求url中是否包含login,如果包含,说明是登陆操作,放行
if (url.contains("login")){
filterChain.doFilter(servletRequest,servletResponse);
}
//3.获取请求头中的令牌(token)
String jwt = req.getHeader("token");
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
if (!StringUtils.hasText(jwt)){
Result error = Result.error("NOT_LOGIN");
String not_login= JSONObject.toJSONString(error);
resp.getWriter().write(not_login);
return;
}
//5.解析token,如果解析失败返回错误结果(未登录)
try {
Claims claims = jwtUtils.parseJWT(jwt);
id = (Integer) claims.get("id");
name = (String) claims.get("name");
username = (String) claims.get("username");
} catch (Exception e) {
//jwt解析失败
e.printStackTrace();
log.info("jwt解析失败,返回未登录信息");
Result error = Result.error("NOT_LOGIN");
String not_login= JSONObject.toJSONString(error);
resp.getWriter().write(not_login);
return;
}
//6.放行
log.info("当前登录者{}信息:id={},name={}",username,id,name);
log.info("jwt合法,放行");
filterChain.doFilter(servletRequest,servletResponse);
}
}
在编写完上述代码后,执行登陆功能会等待超时,前端也一直没有响应。
问题排查:
第一次:
我首先就是给程序打上断点,然后debug情况下再次执行登陆功能。当断点到达“resp.getWriter().write(not_login);”这一行后开始抛出异常,然后就没有给前端发响应了。
但是到这里我还是比较懵,没想明白怎么回事。然后上网一搜,发现有许多人也出现过这个问题,但是点进去他们的具体都是发生在一些下载文档或是其他问题是出现的异常。最终只了解到这个异常是因为这个response.getWriter()方法是和response.getOutputStream()相冲突的。
尝试解决:
既然是和这个方法想冲突,而且我也有response这个对象,那我再每次使用response.getWriter()方法前将这个io流关闭不就行了吗?于是我就在俩处使用getWriter()的地方上增加了
resp.getOutputStream().close();
然后重启服务,再次执行登陆功能。第一次登陆成功了,但是这个异常还在。
第二次:
这个时候看了一下控制台说jwt令牌里信息是id为null,name为null,放行。
这个时候明白了,我这过滤器不应该拦截登陆请求的,那应该就是过滤登陆请求的那个if语句可能出现了问题.
再次debug一排查,发现我代码中成功判断登陆请求放行后继续往下走!!!!
这里应该加个return终止的。然后将之前加的 resp.getOutputStream().close();注释后再第一个if语句中添加return后再次测试。问题就解决了。