如何使用RequestHeaders添加自定義參數(shù)
RequestHeaders添加自定義參數(shù)
在開發(fā)過程中有的時候,參數(shù)需要綁定到requestHeaders中,而并不是在body中進行傳輸。這個時候就需要我們自己定義參數(shù)(需要后臺的配合)
setToken() { let token = localStorage.getItem('token') ? localStorage.getItem('token') : '' this.instance.defaults.headers.common['tokens'] = token } // 使用axios添加requestHeaders參數(shù)。封裝到ajax請求中~
問題一
在瀏覽器的console中報錯:自定義字段不被允許
Request header field自定義字段 is not allowed by Access-Control-Allow-Headers
原因
包含自定義header字段的跨域請求,瀏覽器會先向服務器發(fā)送OPTIONS請求,探測該服務器是否允許自定義的跨域字段。
如果允許,則繼續(xù)實際的POST/GET正常請求,否則,返回標題所示錯誤。
同時在requestHeaders請求中有你定義的字段,但結果不是我們想要的
在responseHeaders中Access-Control-Allow-Headers中表示服務器允許跨域請求的參數(shù)
Access-Control-Allow-Headers: Content-Type, x-requested-with, X-Custom-Header, Authorization,token
解決方案
服務端需要對OPTIONS請求做出應答,應答header中包含Access-Control-Allow-Headers,且值包含options請求中Access-Control-Request-Headers的值。
以下為java服務端filter中設置的OPTIONS請求處理代碼。
@Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { try { HttpServletRequest hreq = (HttpServletRequest) req; HttpServletResponse hresp = (HttpServletResponse) resp; //跨域 hresp.setHeader("Access-Control-Allow-Origin", "*"); //跨域 Header hresp.setHeader("Access-Control-Allow-Methods", "*"); hresp.setHeader("Access-Control-Allow-Headers", "Content-Type,TOKENS"); // 在這里配置你要定義的參數(shù) // 瀏覽器是會先發(fā)一次options請求,如果請求通過,則繼續(xù)發(fā)送正式的post請求 // 配置options的請求返回 if (hreq.getMethod().equals("OPTIONS")) { hresp.setStatus(HttpStatus.SC_OK); // hresp.setContentLength(0); hresp.getWriter().write("OPTIONS returns OK"); return; } // Filter 只是鏈式處理,請求依然轉發(fā)到目的地址。 chain.doFilter(req, resp); } catch (Exception e) { e.printStackTrace(); } }
其中,這個就是所需設置的應答Header:
hresp.setHeader("Access-Control-Allow-Headers", "Content-Type,TOKENS");
* header中對值的大小寫貌似不敏感。
修改request中header的值
在java web開發(fā)中,我們有時候會遇到需要修改request中請求值的問題,雖然這個不是特別常見。初看這是一個簡單的問題,因為我們能通過HttpServletRequest對象拿到我們需要的所有關于當前這個請求的所有信息,想當然的也就可以修改所以這些信息。可實際情況是HttpServletReques中很多的屬性只有getter方法,而沒有setter方法,也就是說我們不可以修改他們。
記得第一次遇到這種問題還是初學編程的時候,最近又遇到這個問題,就記錄一下。最近遇到的是在spring mvc中,使用@RequestBody注解把requestBody中的json映射到java的object。我們知道對于spring mvc來說,這樣使用的時候需要在請求的header里面表明conten-type為application/json。如果完全是自己開發(fā)的系統(tǒng),沒有問題加上就是,但是當和第三方合作的時候,請求的發(fā)起方式就不是我們能控制住的了?,F(xiàn)在的問題是如果使用spring mvc的這種開發(fā)模式,必須要在請求的header中設置content-type為application/json,但是第三方又不方便設置。所以只能在所有針對第三方的API中進行特殊處理。
sping mvc是基于servlet的,我們只要在請求進入servlet之前在header中設置content-type為application/json就ok了,所以理想的修改方式就是加入一個filter?,F(xiàn)在就到了關鍵的問題:怎么修改請求的header值。答案是利用HttpServletRequestWrapper類。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(new CustomeizedRequest((HttpServletRequest) request), response); } private class CustomeizedRequest extends HttpServletRequestWrapper { public CustomeizedRequest(HttpServletRequest request) { super(request); } @Override public Enumeration<String> getHeaders(String name) { if (null != name && name.equals("Content-Type")) { return new Enumeration<String>() { private boolean hasGetted = false; @Override public String nextElement() { if (hasGetted) { throw new NoSuchElementException(); } else { hasGetted = true; return "application/json;charset=utf-8"; } } @Override public boolean hasMoreElements() { return !hasGetted; } }; } return super.getHeaders(name); } }
demo中只重寫了getHeaders方法,實際上嚴謹?shù)淖龇ㄊ莋etHeader(String name)方法也要被重寫。實質上我們還是沒有改變header中的值的能力,但是我們重寫了getHeaders方法,當發(fā)現(xiàn)是我們的Content-Type字段時,只要返回我們想要設置的值就OK了。同理我們可以任意發(fā)揮,根據(jù)實際的情況去重寫相應的方法。
說一下我在這里遇到的一個問題,在開發(fā)過程中使用的maven加jetty插件,運行起來沒有問題。但是測試和生產(chǎn)環(huán)境用的是tomcat,上了測試環(huán)境發(fā)現(xiàn)沒有效果。第一感覺是不同的容器中Content-Type的大小寫或寫法不一樣。打了一個log繼續(xù)測試,發(fā)現(xiàn)tomcat好像根本沒進入我的getHeaders方法,就開始懷疑tomcat和jetty的某些實現(xiàn)不一致,各種查找沒有結果。最后在本地換成tomcat來debug,竟然進入了重寫的getHeaders方法,再一看name的值是:content-type。粗心把log打錯位置了。。。,剛開始猜想的是對的。
所以這里的name.equals("Content-Type")就要考慮大小寫和不同寫法的因素了(比如contenttype或ContentType)。
后來想了一下之所以會出現(xiàn)這個失誤有兩個原因:
- 粗心 log打錯位置
- 自身對于容器不熟悉,而且之前遇到過tomcat和jetty對于某些請求作不同處理的情況,所以就找錯了方向。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
詳細聊一聊JavaWeb中的Request和Response
這篇文章主要給大家介紹了關于JavaWeb中Request和Response的相關資料,文中通過實例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2023-02-02springboot 多環(huán)境配置 yml文件版的實現(xiàn)方法
這篇文章主要介紹了springboot 多環(huán)境配置 yml文件版的實現(xiàn)方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06mall整合SpringSecurity及JWT實現(xiàn)認證授權實戰(zhàn)
這篇文章主要為大家介紹了mall整合SpringSecurity及JWT實現(xiàn)認證授權實戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06Spring?Boot接口支持高并發(fā)具體實現(xiàn)代碼
這篇文章主要給大家介紹了關于Spring?Boot接口支持高并發(fā)具體實現(xiàn)的相關資料,在SpringBoot項目中通常我們沒有處理并發(fā)問題,但是使用項目本身還是支持一定的并發(fā)量,需要的朋友可以參考下2023-08-08Spring data elasticsearch使用方法詳解
這篇文章主要介紹了Spring data elasticsearch使用方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-01-01Java中FTPClient上傳中文目錄、中文文件名亂碼問題解決方法
這篇文章主要介紹了Java中FTPClient上傳中文目錄、中文文件名亂碼問題解決方法,本文使用apache-commons-net工具包時遇到這個問題,解決方法很簡單,需要的朋友可以參考下2015-05-05Spring Boot項目利用Redis實現(xiàn)session管理實例
本篇文章主要介紹了Spring Boot項目利用Redis實現(xiàn)session管理實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06