好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

如何给HttpServletRequest增加消息头

HttpServletRequest增加header

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

  class MutableHttpServletRequest extends HttpServletRequestWrapper { // holds custom header and value mapping private final Map < String , String > customHeaders ; public MutableHttpServletRequest ( HttpServletRequest request ){ super ( request ); this . customHeaders = new HashMap < String , String >(); }   public void putHeader ( String name , String value ){ this . customHeaders . put ( name , value ); }   public String getHeader ( String name ) { // check the custom headers first String headerValue = customHeaders . get ( name );   if ( headerValue != null ){ return headerValue ; } // else return from into the original wrapped object return (( HttpServletRequest ) getRequest ()). getHeader ( name ); }   public Enumeration < String > getHeaderNames () { // create a set of the custom header names Set < String > set = new HashSet < String >( customHeaders . keySet ());   // now add the headers from the wrapped request object @SuppressWarnings ( "unchecked" ) Enumeration < String > e = (( HttpServletRequest ) getRequest ()). getHeaderNames (); while ( e . hasMoreElements ()) { // add the names of the request headers into the list String n = e . nextElement (); set . add ( n ); }   // create an enumeration from the set and return return Collections . enumeration ( set ); } }

使用:

public class SecurityFilter implements javax . servlet . Filter { @Override public void destroy () { }   @Override public void doFilter ( ServletRequest request , ServletResponse response , FilterChain chain ) throws IOException , ServletException { HttpServletRequest req = ( HttpServletRequest ) request ; MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest ( req ); ... mutableRequest . putHeader ( "x-custom-header" , "custom value" ); chain . doFilter ( mutableRequest , response ); }   @Override public void init ( FilterConfig filterConfig ) throws ServletException { } }

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

@Component public class AccessFilter extends ZuulFilter { private Logger log = LoggerFactory . getLogger ( AccessFilter . class ); @Autowired private VerificationHelper helper ; private BufferedReader reader = null ; @Autowired private KeyAndFrequencyService service ; @Autowired private ZuulTest zuulTest ; @Autowired private PermissionHandler permissionHandler ; @Override public String filterType () { //前置过滤器 return "pre" ; } @Override public int filterOrder () { //优先级,数字越大,优先级越低 return 0 ; } @Override public boolean shouldFilter () { //是否执行该过滤器,true代表需要过滤 return true ; } @Override public Object run () { RequestContext ctx = RequestContext . getCurrentContext (); HttpServletRequest request = ctx . getRequest (); try { permissionHandler . setTokenExpireTime ( 200000000 ); String type = request . getHeader ( "type" ); zuulTest . say (); System . out . println ( "......................................................" ); if ( type == null ) { System . out . println ( "......................................................验证1" ); Object object = helper . AccessZuul ( request , ctx ); return object ; } else { System . out . println ( "......................................................验证2" ); PermissionResult result = permissionHandler . check ( request ); System . out . println ( result ); if ( result . isState ()){   MutableHttpServletRequest mutRequest = new MutableHttpServletRequest ( request ); //增加头部信息 DasAccountInfo accountInfo = permissionHandler . GetDasAccountInfoById ( Integer . parseInt ( result . getUserId ()));   mutRequest . putHeader ( "dasAccountInfo" , JSON . toJSONString ( disablePropertyName ())) ; RequestContext . getCurrentContext (). setRequest ( mutRequest ); ctx . setSendZuulResponse ( true ); // 对该请求进行路由 ctx . setResponseStatusCode ( 200 ); ctx . set ( "isSuccess" , true ); } else { ctx . setSendZuulResponse ( false ); // 过滤该请求,不对其进行路由 ctx . setResponseStatusCode ( 401 ); // 返回错误码 ctx . setResponseBody ( "{\"code\":0,\"result\":\"网关验证失败!验证方式为2\"}" ); // 返回错误内容 ctx . set ( "isSuccess" , false ); } } } catch ( Exception e ){ e . printStackTrace (); log . error ( "网关报错!!!" , e . fillInStackTrace ()); } return null ; }

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

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

修改HttpServletRequest中header的信息

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

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

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

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

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

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

gsid = request . getParameter ( "GSID" );

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

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

解释:

/** * 修改header信息,key-value键值对儿加入到header中 * @param request * @param key * @param value */ private void reflectSetparam ( HttpServletRequest request , String key , String value ){ Class <? extends HttpServletRequest > requestClass = request . getClass (); System . out . println ( "request实现类=" + requestClass . getName ()); try { Field request1 = requestClass . getDeclaredField ( "request" ); request1 . setAccessible ( true ); Object o = request1 . get ( request ); Field coyoteRequest = o . getClass (). getDeclaredField ( "coyoteRequest" ); coyoteRequest . setAccessible ( true ); Object o1 = coyoteRequest . get ( o ); System . out . println ( "coyoteRequest实现类=" + o1 . getClass (). getName ()); Field headers = o1 . getClass (). getDeclaredField ( "headers" ); headers . setAccessible ( true ); MimeHeaders o2 = ( MimeHeaders ) headers . get ( o1 ); o2 . addValue ( key ). setString ( value ); } catch ( Exception e ) { e . printStackTrace (); } }

执行打印信息如下:

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

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

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

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

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

public String getHeader ( String name ) { if ( this . request == null ) { throw new IllegalStateException ( sm . getString ( "requestFacade.nullRequest" )); } else { return this . request . getHeader ( name ); } }

然后我们找this.request

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

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

这个类中找getHeader方法

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

找到这个类中的coyoteRequest

protected org . apache . coyote . Request coyoteRequest ;

是这样的

再找到getHeader()

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

好了,终于见到属性了

private final MimeHeaders headers = new MimeHeaders ();

找到MineHeaders中的getHeader方法,

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

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

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

这里有name,value,靠谱

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

测试请求:

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

测试打印结果:

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

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

查看更多关于如何给HttpServletRequest增加消息头的详细内容...

  阅读:46次