如何給HttpServletRequest增加消息頭
HttpServletRequest增加header
由于在請(qǐng)求中請(qǐng)求域的屬性在請(qǐng)求轉(zhuǎn)發(fā),路由等過(guò)程中,請(qǐng)求域的值會(huì)丟失,在項(xiàng)目項(xiàng)目中使用請(qǐng)求頭來(lái)傳遞信息,但是HttpRequest并沒(méi)有實(shí)現(xiàn)增加請(qǐng)求頭的方法,所以找到他的子類來(lái)實(shí)現(xiàn)
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 { } }
但是項(xiàng)目中我使用的SpringCloud ZUUL中使用這樣 的方式失?。?/p>
@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() { //前置過(guò)濾器 return "pre"; } @Override public int filterOrder() { //優(yōu)先級(jí),數(shù)字越大,優(yōu)先級(jí)越低 return 0; } @Override public boolean shouldFilter() { //是否執(zhí)行該過(guò)濾器,true代表需要過(guò)濾 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("......................................................驗(yàn)證1"); Object object = helper.AccessZuul(request, ctx); return object; } else { System.out.println("......................................................驗(yàn)證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);// 對(duì)該請(qǐng)求進(jìn)行路由 ctx.setResponseStatusCode(200); ctx.set("isSuccess", true); }else{ ctx.setSendZuulResponse(false);// 過(guò)濾該請(qǐng)求,不對(duì)其進(jìn)行路由 ctx.setResponseStatusCode(401);// 返回錯(cuò)誤碼 ctx.setResponseBody("{\"code\":0,\"result\":\"網(wǎng)關(guān)驗(yàn)證失敗!驗(yàn)證方式為2\"}");// 返回錯(cuò)誤內(nèi)容 ctx.set("isSuccess", false); } } }catch (Exception e){ e.printStackTrace(); log.error("網(wǎng)關(guān)報(bào)錯(cuò)?。?!",e.fillInStackTrace()); } return null; }
使用zuul網(wǎng)關(guān)的自帶的設(shè)置請(qǐng)求頭的方法,在網(wǎng)關(guān)中設(shè)置的請(qǐng)求頭可以被路由下面的服務(wù)獲取到:
ctx.getZuulRequestHeaders().put("dasAccountInfo", JSON.toJSONString(disablePropertyName()));
修改HttpServletRequest中header的信息
廢話一堆:由于業(yè)務(wù)有統(tǒng)一的鑒權(quán)系統(tǒng),頁(yè)面請(qǐng)求時(shí)在header中帶過(guò)來(lái)gsid,正常業(yè)務(wù)沒(méi)有問(wèn)題,但是當(dāng)需要下載文件時(shí),前端統(tǒng)一用json解析響應(yīng),當(dāng)響應(yīng)文件時(shí),對(duì)于前端來(lái)說(shuō)不好處理,就決定使用簡(jiǎn)單的get請(qǐng)求下載文件,將gsid通過(guò)url帶過(guò)來(lái),這樣的話后端鑒權(quán)就需要處理,當(dāng)header中沒(méi)有g(shù)sid時(shí),從參數(shù)中取,為了盡可能少的改變公用的業(yè)務(wù)代碼(指sso),就在當(dāng)前項(xiàng)目中自定義權(quán)限攔截器。
總結(jié)一句,我就是想想header中加?xùn)|西!!往下看具體實(shí)現(xiàn)方式:
新建攔截器類,繼承原有的攔截器,重寫其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設(shè)置到request中的的header中去 reflectSetparam(request,"GSID",gsid); log.info("請(qǐng)求連接中的gsid={}",request.getHeader("GSID")); } return super.preHandle(request, response, o); }
說(shuō)明:可以看到在方法中,
1、先進(jìn)行header信息判斷,如果header中沒(méi)有GSID,就去請(qǐng)求參數(shù)中拿
gsid= request.getParameter("GSID");
2、通過(guò)反射將參數(shù)中的GSID鍵值對(duì)兒:“GSID”:“376645354562335”加入到header中去
話不多少,先上代碼,再解釋:
解釋:
/** * 修改header信息,key-value鍵值對(duì)兒加入到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實(shí)現(xiàn)類="+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實(shí)現(xiàn)類="+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(); } }
執(zhí)行打印信息如下:
request實(shí)現(xiàn)類=org.apache.catalina.connector.RequestFacade
coyoteRequest實(shí)現(xiàn)類=org.apache.coyote.Request
看HttpServletRequest的源碼,是個(gè)接口,并且我們獲取header信息的方法是getHeader()方法,按常理其對(duì)象中應(yīng)該有header字段,那么我們就去實(shí)現(xiàn)類中找這個(gè)字段,具體過(guò)程如下
步驟一:先找到具體的Request對(duì)象是哪個(gè)類,根據(jù)打印信息看源碼
進(jìn)入其中找到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
這個(gè)request,我們找到它的類型,點(diǎn)擊去
這個(gè)類的全路徑是:org.apache.catalina.connector.Request
這個(gè)類中找getHeader方法
public String getHeader(String name) { return this.coyoteRequest.getHeader(name); }
找到這個(gè)類中的coyoteRequest
protected org.apache.coyote.Request coyoteRequest;
是這樣的
再找到getHeader()
public String getHeader(String name) { return this.headers.getHeader(name); }
好了,終于見(jiàn)到屬性了
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是一個(gè)MessageBytes對(duì)象,好找到這個(gè)對(duì)象進(jìn)去,發(fā)現(xiàn)只能setValue,那就在MineHeaders中找在哪里實(shí)例化MessageBytes對(duì)象的
找了半天找到在createHeader()方法中實(shí)例化MimeHeaderField對(duì)象,然后這個(gè)對(duì)象實(shí)例化時(shí)會(huì)實(shí)例化MessageBytes對(duì)象
這里有name,value,靠譜
然后再在MimeHeader中找在addValue方法中有調(diào)用,就用這個(gè)試一下吧,然后就是最上面的我自定義的方法,在heade中加入了一個(gè)鍵值對(duì)兒。
測(cè)試請(qǐng)求:
http://127.0.0.1:32100/v1/CustomerRefundRest/exportRefund?gsid=abc114f1bd0d484084e5df3fe1c419b8&refundLongStartDate=1520611199000&refundLongEndDate=1522943999000
測(cè)試打印結(jié)果:
OVER!以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring?webClient配置及使用簡(jiǎn)單代碼示例
WebClient是Spring框架5.0引入的基于響應(yīng)式編程模型的HTTP客戶端,它提供一種簡(jiǎn)便的方式來(lái)處理HTTP請(qǐng)求和響應(yīng),支持異步和非阻塞式的請(qǐng)求和響應(yīng)處理,下面這篇文章主要給大家介紹了關(guān)于spring?webClient配置及使用的相關(guān)資料,需要的朋友可以參考下2024-03-03Spring Boot 中嵌入式 Servlet 容器自動(dòng)配置原理解析
這篇文章主要介紹了Spring Boot 中嵌入式 Servlet 容器自動(dòng)配置原理解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11SpringBoot整合Web開發(fā)之Json數(shù)據(jù)返回的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot整合Web開發(fā)其中Json數(shù)據(jù)返回的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Hibernate映射解析之關(guān)聯(lián)映射詳解
所謂關(guān)聯(lián)映射就是將關(guān)聯(lián)關(guān)系映射到數(shù)據(jù)庫(kù)里,在對(duì)象模型中就是一個(gè)或多個(gè)引用。下面這篇文章詳細(xì)的給大家介紹了Hibernate映射解析之關(guān)聯(lián)映射的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-02-02Windows中使用Java生成Excel文件并插入圖片的方法
這篇文章主要介紹了Windows中使用Java生成Excel文件并插入圖片的方法,其中向Excel中插入圖片文中通過(guò)使用Apache POI來(lái)實(shí)現(xiàn),需要的朋友可以參考下2016-02-02java打印表格 將ResultSet中的數(shù)據(jù)打印成表格問(wèn)題
這篇文章主要介紹了java打印表格 將ResultSet中的數(shù)據(jù)打印成表格問(wèn)題。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12