如何給HttpServletRequest增加消息頭
HttpServletRequest增加header
由于在請求中請求域的屬性在請求轉(zhuǎn)發(fā),路由等過程中,請求域的值會丟失,在項目項目中使用請求頭來傳遞信息,但是HttpRequest并沒有實現(xiàn)增加請求頭的方法,所以找到他的子類來實現(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 {
}
}
但是項目中我使用的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() {
//前置過濾器
return "pre";
}
@Override
public int filterOrder() {
//優(yōu)先級,數(shù)字越大,優(yōu)先級越低
return 0;
}
@Override
public boolean shouldFilter() {
//是否執(zhí)行該過濾器,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\":\"網(wǎng)關(guān)驗證失敗!驗證方式為2\"}");// 返回錯誤內(nèi)容
ctx.set("isSuccess", false);
}
}
}catch (Exception e){
e.printStackTrace();
log.error("網(wǎng)關(guān)報錯?。?!",e.fillInStackTrace());
}
return null;
}
使用zuul網(wǎng)關(guān)的自帶的設(shè)置請求頭的方法,在網(wǎng)關(guān)中設(shè)置的請求頭可以被路由下面的服務(wù)獲取到:
ctx.getZuulRequestHeaders().put("dasAccountInfo", JSON.toJSONString(disablePropertyName()));
修改HttpServletRequest中header的信息
廢話一堆:由于業(yè)務(wù)有統(tǒng)一的鑒權(quán)系統(tǒng),頁面請求時在header中帶過來gsid,正常業(yè)務(wù)沒有問題,但是當需要下載文件時,前端統(tǒng)一用json解析響應(yīng),當響應(yīng)文件時,對于前端來說不好處理,就決定使用簡單的get請求下載文件,將gsid通過url帶過來,這樣的話后端鑒權(quán)就需要處理,當header中沒有g(shù)sid時,從參數(shù)中取,為了盡可能少的改變公用的業(yè)務(wù)代碼(指sso),就在當前項目中自定義權(quán)限攔截器。
總結(jié)一句,我就是想想header中加?xùn)|西?。⊥驴?/strong>具體實現(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("請求連接中的gsid={}",request.getHeader("GSID"));
}
return super.preHandle(request, response, o);
}
說明:可以看到在方法中,
1、先進行header信息判斷,如果header中沒有GSID,就去請求參數(shù)中拿
gsid= request.getParameter("GSID");
2、通過反射將參數(shù)中的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實現(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實現(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實現(xiàn)類=org.apache.catalina.connector.RequestFacade
coyoteRequest實現(xiàn)類=org.apache.coyote.Request
看HttpServletRequest的源碼,是個接口,并且我們獲取header信息的方法是getHeader()方法,按常理其對象中應(yīng)該有header字段,那么我們就去實現(xiàn)類中找這個字段,具體過程如下
步驟一:先找到具體的Request對象是哪個類,根據(jù)打印信息看源碼
進入其中找到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對象,好找到這個對象進去,發(fā)現(xiàn)只能setValue,那就在MineHeaders中找在哪里實例化MessageBytes對象的
找了半天找到在createHeader()方法中實例化MimeHeaderField對象,然后這個對象實例化時會實例化MessageBytes對象

這里有name,value,靠譜
然后再在MimeHeader中找在addValue方法中有調(diào)用,就用這個試一下吧,然后就是最上面的我自定義的方法,在heade中加入了一個鍵值對兒。
測試請求:
http://127.0.0.1:32100/v1/CustomerRefundRest/exportRefund?gsid=abc114f1bd0d484084e5df3fe1c419b8&refundLongStartDate=1520611199000&refundLongEndDate=1522943999000
測試打印結(jié)果:


OVER!以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Boot 中嵌入式 Servlet 容器自動配置原理解析
這篇文章主要介紹了Spring Boot 中嵌入式 Servlet 容器自動配置原理解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringBoot整合Web開發(fā)之Json數(shù)據(jù)返回的實現(xiàn)
這篇文章主要介紹了SpringBoot整合Web開發(fā)其中Json數(shù)據(jù)返回的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
Hibernate映射解析之關(guān)聯(lián)映射詳解
所謂關(guān)聯(lián)映射就是將關(guān)聯(lián)關(guān)系映射到數(shù)據(jù)庫里,在對象模型中就是一個或多個引用。下面這篇文章詳細的給大家介紹了Hibernate映射解析之關(guān)聯(lián)映射的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-02-02
Windows中使用Java生成Excel文件并插入圖片的方法
這篇文章主要介紹了Windows中使用Java生成Excel文件并插入圖片的方法,其中向Excel中插入圖片文中通過使用Apache POI來實現(xiàn),需要的朋友可以參考下2016-02-02
java打印表格 將ResultSet中的數(shù)據(jù)打印成表格問題
這篇文章主要介紹了java打印表格 將ResultSet中的數(shù)據(jù)打印成表格問題。具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12

