在使用react開發時遇到了先後端分離post請求跨域的問題,致使請求沒法正常完成。javascript
當客戶端向服務器發起一個網絡請求,url會有包含三個主要信息:協議(protocol),域名(host),端口號(port)。當三部分都和服務器相同的狀況下,屬於同源。可是隻要有一個不一樣,就屬於構成了跨域調用。會受到同源策略的限制。html
同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制。瀏覽器的同源策略,出於防範跨站腳本的攻擊,禁止客戶端腳本(如 JavaScript)對不一樣域的服務進行跨站調用(一般指使用XMLHttpRequest請求)。
java
JSONP(json with padding 填充式json),利用了使用src引用靜態資源時不受跨域限制的機制。主要在客戶端搞一個回調作一些數據接收與操做的處理,並把這個回調函數名告知服務端,而服務端須要作的是按照javascript的語法把數據放到約定好的回調函數之中便可。jQuery很早以前就已經吧JSONP語法糖化了,使用起來會更加方便。react
jsonp的簡單實現:jquery
1 // 回調函數 2 function jsonpCallback(data) { 3 console.log("jsonpCallback: " + data.name) 4 } 5 $("#submit").click(function() { 6 var data = { 7 name: $("#name").val(), 8 id: $("#id").val() 9 }; 10 $.ajax({ 11 url: 'http://localhost:3001/ajax/deal', 12 data: data, 13 dataType: 'jsonp', 14 cache: false, 15 timeout: 5000, 16 // jsonp 字段含義爲服務器經過什麼字段獲取回調函數的名稱 17 jsonp: 'callback', 18 // 聲明本地回調函數的名稱,jquery 默認隨機生成一個函數名稱 19 jsonpCallback: 'jsonpCallback', 20 success: function(data) { 21 console.log("ajax success callback: " + data.name) 22 }, 23 error: function(jqXHR, textStatus, errorThrown) { 24 console.log(textStatus + ' ' + errorThrown); 25 } 26 }); 27 });
CORS(Cross-origin resource sharing 跨域資源共享),依附於AJAX,經過添加HTTP Hearder部分字段請求與獲取有權限訪問的資源。CORS對開發者是透明的,由於瀏覽器會自動根據請求的狀況(簡單和複雜)作出不一樣的處理。CORS的關鍵是服務端的配置支持。因爲CORS是W3C中一項較「新」的方案,以致於各大網頁解析引擎尚未對其進行嚴格規格的實現,因此不一樣引擎下可能會有一些不一致。webpack
(1)Access-Control-Allow-Originnginx
該字段是必須的。它的值要麼是請求時Origin
字段的值,要麼是一個*
,表示接受任意域名的請求。web
(2)Access-Control-Allow-Credentialsajax
該字段可選。它的值是一個布爾值,表示是否容許發送Cookie。默認狀況下,Cookie不包括在CORS請求之中。設爲true
,即表示服務器明確許可,Cookie能夠包含在請求中,一塊兒發給服務器。這個值也只能設爲true
,若是服務器不要瀏覽器發送Cookie,刪除該字段便可。若是要發送Cookie,Access-Control-Allow-Origin
就不能設爲星號,必須指定明確的、與請求網頁一致的域名。同時,Cookie依然遵循同源政策,只有用服務器域名設置的Cookie纔會上傳,其餘域名的Cookie並不會上傳,且(跨源)原網頁代碼中的document.cookie
也沒法讀取服務器域名下的Cookie。json
(3)Access-Control-Expose-Headers
該字段可選。CORS請求時,XMLHttpRequest
對象的getResponseHeader()
方法只能拿到6個基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers
裏面指定。上面的例子指定,getResponseHeader('FooBar')
能夠返回FooBar
字段的值。
java過濾器實現cors:
1 public class CorsFilter implements Filter { 2 3 public void init(FilterConfig filterConfig) throws ServletException { 4 } 5 6 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 7 throws IOException, ServletException { 8 HttpServletResponse httpResponse = (HttpServletResponse) response; 9 httpResponse.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");//設置容許跨域的域名,須要發送cookie信息,因此此處須要指定具體的域名, 10 httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 11 httpResponse.setHeader("Access-Control-Allow-Methods", "GET, PUT, DELETE, POST");//容許跨域的請求方式 12 /** 13 * ajax請求的時候若是帶有xhrFields:{withCredentials:true}, 14 * 那麼服務器後臺在配置跨域的時候就必需要把Access-Control-Allow-Credentials這個請求頭加上去 15 */ 16 httpResponse.setHeader("Access-Control-Allow-Credentials", "true");//容許發送Cookie信息 17 httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // 支持HTTP 1.1. 18 httpResponse.setHeader("Pragma", "no-cache"); // 支持HTTP 1.0. response.setHeader("Expires", "0"); 19 chain.doFilter(request, response); 20 } 21 22 public void destroy() { 23 // TODO Auto-generated method stub 24 } 25 }
二者優勢與缺點大體互補,放在一塊介紹:
代理的話其實也可使用nginx反向代理,可是配置的時候發現請求過程老是處於(pending)等待狀態,好久才能響應,不知是何緣由引發,還未解決,若有大牛看到,肯請指教。
nginx配置以下:
1 location ^~/ { 2 proxy_pass http://localhost:8080; 3 proxy_redirect default ; 4 proxy_set_header Host $host:80; 5 proxy_set_header X-Real-IP $remote_addr; 6 proxy_set_header REMOTE-HOST $remote_addr; 7 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 8 9 10 }
由於失敗了,因此轉而使用webpack代理配置:
首先在webpack.config.js中進行配置:
module.exports = {
//。。。省略
devServer: {
port: '8081',
host: '127.0.0.1',
historyApiFallback: false,
disableHostCheck: true,
noInfo: false,
stats: 'minimal',
inline: true,
//開啓服務器的模塊熱替換(HMR)
hot: true,
// 和上文 output 的「publicPath」值保持一致
publicPath: context,
proxy: { '/sharemeeting/*': { target: "http://localhost:8080", changeOrigin: true, secure: false } }
}
//。。。省略
};
proxy中,'/sharemeeting/*'是過濾要代理的請求的路徑,tartget爲代理後的目標服務器地址,包括協議、域名、端口號信息。若是發起的請求爲http://localhost:8081/sharemeeting/getTest.do。那麼將會被代理爲http://localhost:8080/sharemeeting/getTest.do。
fetch請求
1 let url = "/sharemeeting/login/getTest.do"; 2 fetch(url,{ 3 method: 'POST', 4 headers: { 5 'Accept': 'application/json', 6 'Content-Type': 'application/json' 7 }, 8 credentials: 'include', 9 body: JSON.stringify({}) 10 }).then((response) => response.json()) //把response轉爲json 11 .then((responseData) => { // 上面的轉好的json 12 if(responseData.status === false){ 13 window.location.href="#/"; 14 }else{ 15 this.reset(responseData.data); 16 } 17 }).catch((error)=> { 18 window.location.href="#/"; 19 })
請求的url要像上面這樣定義,若是這樣定義,這樣請求的時候會本身添加上協議和請求的域名端口號,
======================================參考=================================
1.https://www.zhihu.com/question/41992168 JS跨域方案JSONP與CORS的各自優缺點以及應用場景?
2.http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html 瀏覽器同源政策及其規避方法
3.http://www.ruanyifeng.com/blog/2016/04/cors.html 跨域資源共享 CORS 詳解
4.https://www.jianshu.com/p/3bdff821f859 Webpack dev server使用http-proxy解決跨域問題