服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 如何给HttpServletRequest增加消息头

如何给HttpServletRequest增加消息头

2021-09-19 10:31meihuiziaaaaaa Java教程

这篇文章主要介绍了如何给HttpServletRequest增加消息头的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

HttpServletRequest增加header

由于在请求中请求域的属性在请求转发,路由等过程中,请求域的值会丢失,在项目项目中使用请求头来传递信息,但是HttpRequest并没有实现增加请求头的方法,所以找到他的子类来实现

  1.  
  2. class MutableHttpServletRequest extends HttpServletRequestWrapper {
  3. // holds custom header and value mapping
  4. private final Map<String, String> customHeaders;
  5. public MutableHttpServletRequest(HttpServletRequest request){
  6. super(request);
  7. this.customHeaders = new HashMap<String, String>();
  8. }
  9.  
  10. public void putHeader(String name, String value){
  11. this.customHeaders.put(name, value);
  12. }
  13.  
  14. public String getHeader(String name) {
  15. // check the custom headers first
  16. String headerValue = customHeaders.get(name);
  17.  
  18. if (headerValue != null){
  19. return headerValue;
  20. }
  21. // else return from into the original wrapped object
  22. return ((HttpServletRequest) getRequest()).getHeader(name);
  23. }
  24.  
  25. public Enumeration<String> getHeaderNames() {
  26. // create a set of the custom header names
  27. Set<String> set = new HashSet<String>(customHeaders.keySet());
  28.  
  29. // now add the headers from the wrapped request object
  30. @SuppressWarnings("unchecked")
  31. Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
  32. while (e.hasMoreElements()) {
  33. // add the names of the request headers into the list
  34. String n = e.nextElement();
  35. set.add(n);
  36. }
  37.  
  38. // create an enumeration from the set and return
  39. return Collections.enumeration(set);
  40. }
  41. }

使用:

  1. public class SecurityFilter implements javax.servlet.Filter {
  2. @Override
  3. public void destroy() {
  4. }
  5.  
  6. @Override
  7. public void doFilter(ServletRequest request, ServletResponse response,
  8. FilterChain chain) throws IOException, ServletException {
  9. HttpServletRequest req = (HttpServletRequest) request;
  10. MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(req);
  11. ...
  12. mutableRequest.putHeader("x-custom-header", "custom value");
  13. chain.doFilter(mutableRequest, response);
  14. }
  15.  
  16. @Override
  17. public void init(FilterConfig filterConfig) throws ServletException {
  18. }
  19. }

但是项目中我使用的SpringCloud ZUUL中使用这样 的方式失败:

  1. @Component
  2. public class AccessFilter extends ZuulFilter {
  3. private Logger log = LoggerFactory.getLogger(AccessFilter.class);
  4. @Autowired
  5. private VerificationHelper helper;
  6. private BufferedReader reader=null;
  7. @Autowired
  8. private KeyAndFrequencyService service;
  9. @Autowired
  10. private ZuulTest zuulTest;
  11. @Autowired
  12. private PermissionHandler permissionHandler;
  13. @Override
  14. public String filterType() {
  15. //前置过滤器
  16. return "pre";
  17. }
  18. @Override
  19. public int filterOrder() {
  20. //优先级,数字越大,优先级越低
  21. return 0;
  22. }
  23. @Override
  24. public boolean shouldFilter() {
  25. //是否执行该过滤器,true代表需要过滤
  26. return true;
  27. }
  28. @Override
  29. public Object run() {
  30. RequestContext ctx = RequestContext.getCurrentContext();
  31. HttpServletRequest request = ctx.getRequest();
  32. try {
  33. permissionHandler.setTokenExpireTime(200000000);
  34. String type = request.getHeader("type");
  35. zuulTest.say();
  36. System.out.println("......................................................");
  37. if (type == null) {
  38. System.out.println("......................................................验证1");
  39. Object object = helper.AccessZuul(request, ctx);
  40. return object;
  41. } else {
  42. System.out.println("......................................................验证2");
  43. PermissionResult result=permissionHandler.check(request);
  44. System.out.println(result);
  45. if(result.isState()){
  46.  
  47. MutableHttpServletRequest mutRequest=new MutableHttpServletRequest (request);
  48. //增加头部信息
  49. DasAccountInfo accountInfo= permissionHandler.GetDasAccountInfoById(Integer.parseInt(result.getUserId()));
  50.  
  51. mutRequest.putHeader("dasAccountInfo", JSON.toJSONString(disablePropertyName())) ;RequestContext.getCurrentContext().setRequest(mutRequest);
  52. ctx.setSendZuulResponse(true);// 对该请求进行路由
  53. ctx.setResponseStatusCode(200);
  54. ctx.set("isSuccess", true);
  55. }else{
  56. ctx.setSendZuulResponse(false);// 过滤该请求,不对其进行路由
  57. ctx.setResponseStatusCode(401);// 返回错误码
  58. ctx.setResponseBody("{\"code\":0,\"result\":\"网关验证失败!验证方式为2\"}");// 返回错误内容
  59. ctx.set("isSuccess", false);
  60. }
  61. }
  62. }catch (Exception e){
  63. e.printStackTrace();
  64. log.error("网关报错!!!",e.fillInStackTrace());
  65. }
  66. return null;
  67. }

使用zuul网关的自带的设置请求头的方法,在网关中设置的请求头可以被路由下面的服务获取到:

  1. ctx.getZuulRequestHeaders().put("dasAccountInfo", JSON.toJSONString(disablePropertyName()));

修改HttpServletRequest中header的信息

废话一堆:由于业务有统一的鉴权系统,页面请求时在header中带过来gsid,正常业务没有问题,但是当需要下载文件时,前端统一用json解析响应,当响应文件时,对于前端来说不好处理,就决定使用简单的get请求下载文件,将gsid通过url带过来,这样的话后端鉴权就需要处理,当header中没有gsid时,从参数中取,为了尽可能少的改变公用的业务代码(指sso),就在当前项目中自定义权限拦截器。

总结一句,我就是想想header中加东西!!往下看具体实现方式:

新建拦截器类,继承原有的拦截器,重写其preHandle方法

  1. @Override
  2. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
  3. String gsid = request.getHeader("GSID");
  4. if(StringUtils.isBlank(gsid)){
  5. String gsid= request.getParameter("GSID");
  6. //使用反射,将gsid设置到request中的的header中去
  7. reflectSetparam(request,"GSID",gsid);
  8. log.info("请求连接中的gsid={}",request.getHeader("GSID"));
  9. }
  10. return super.preHandle(request, response, o);
  11. }

说明:可以看到在方法中,

1、先进行header信息判断,如果header中没有GSID,就去请求参数中拿

  1. gsid= request.getParameter("GSID");

2、通过反射将参数中的GSID键值对儿:“GSID”:“376645354562335”加入到header中去

话不多少,先上代码,再解释:

解释:

  1. /**
  2. * 修改header信息,key-value键值对儿加入到header中
  3. * @param request
  4. * @param key
  5. * @param value
  6. */
  7. private void reflectSetparam(HttpServletRequest request,String key,String value){
  8. Class<? extends HttpServletRequest> requestClass = request.getClass();
  9. System.out.println("request实现类="+requestClass.getName());
  10. try {
  11. Field request1 = requestClass.getDeclaredField("request");
  12. request1.setAccessible(true);
  13. Object o = request1.get(request);
  14. Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
  15. coyoteRequest.setAccessible(true);
  16. Object o1 = coyoteRequest.get(o);
  17. System.out.println("coyoteRequest实现类="+o1.getClass().getName());
  18. Field headers = o1.getClass().getDeclaredField("headers");
  19. headers.setAccessible(true);
  20. MimeHeaders o2 = (MimeHeaders)headers.get(o1);
  21. o2.addValue(key).setString(value);
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. }

执行打印信息如下:

request实现类=org.apache.catalina.connector.RequestFacade

coyoteRequest实现类=org.apache.coyote.Request

看HttpServletRequest的源码,是个接口,并且我们获取header信息的方法是getHeader()方法,按常理其对象中应该有header字段,那么我们就去实现类中找这个字段,具体过程如下

步骤一:先找到具体的Request对象是哪个类,根据打印信息看源码

进入其中找到getHeader()方法,如下

  1. public String getHeader(String name) {
  2. if (this.request == null) {
  3. throw new IllegalStateException(sm.getString("requestFacade.nullRequest"));
  4. } else {
  5. return this.request.getHeader(name);
  6. }
  7. }

然后我们找this.request

如何给HttpServletRequest增加消息头

这个request,我们找到它的类型,点击去

如何给HttpServletRequest增加消息头

这个类的全路径是:org.apache.catalina.connector.Request

这个类中找getHeader方法

  1. public String getHeader(String name) {
  2. return this.coyoteRequest.getHeader(name);
  3. }

找到这个类中的coyoteRequest

  1. protected org.apache.coyote.Request coyoteRequest;

是这样的

如何给HttpServletRequest增加消息头

再找到getHeader()

  1. public String getHeader(String name) {
  2. return this.headers.getHeader(name);
  3. }

好了,终于见到属性了

  1. private final MimeHeaders headers = new MimeHeaders();

找到MineHeaders中的getHeader方法,

  1. public String getHeader(String name) {
  2. MessageBytes mh = this.getValue(name);
  3. return mh != null ? mh.toString() : null;
  4. }

看到最终header是一个MessageBytes对象,好找到这个对象进去,发现只能setValue,那就在MineHeaders中找在哪里实例化MessageBytes对象的

找了半天找到在createHeader()方法中实例化MimeHeaderField对象,然后这个对象实例化时会实例化MessageBytes对象

如何给HttpServletRequest增加消息头

这里有name,value,靠谱

然后再在MimeHeader中找在addValue方法中有调用,就用这个试一下吧,然后就是最上面的我自定义的方法,在heade中加入了一个键值对儿。

测试请求:

http://127.0.0.1:32100/v1/CustomerRefundRest/exportRefund?gsid=abc114f1bd0d484084e5df3fe1c419b8&refundLongStartDate=1520611199000&refundLongEndDate=1522943999000

测试打印结果:

如何给HttpServletRequest增加消息头如何给HttpServletRequest增加消息头

OVER!以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

原文链接:https://blog.csdn.net/didi7696/article/details/83508499

延伸 · 阅读

精彩推荐