關於先後端分離跨域請求問題

1.問題描述:

  在使用react開發時遇到了先後端分離post請求跨域的問題,致使請求沒法正常完成。javascript

2.什麼是跨域?

  當客戶端向服務器發起一個網絡請求,url會有包含三個主要信息:協議(protocol),域名(host),端口號(port)。當三部分都和服務器相同的狀況下,屬於同源。可是隻要有一個不一樣,就屬於構成了跨域調用。會受到同源策略的限制。html

  同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制。瀏覽器的同源策略,出於防範跨站腳本的攻擊,禁止客戶端腳本(如 JavaScript)對不一樣域的服務進行跨站調用(一般指使用XMLHttpRequest請求)。
java

3.幾種跨域解決方式:

3.1. jsonp請求:

  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 });

 

3.2 cors跨域資源共享

  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-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。若是想拿到其餘字段,就必須在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 }

 

jsonp和cors的不一樣:

  二者優勢與缺點大體互補,放在一塊介紹:

  1. JSONP的主要優點在於對瀏覽器的支持較好;雖然目前主流瀏覽器支持CORS,但IE10如下不支持CORS。
  2. JSONP只能用於獲取資源(即只讀,相似於GET請求);CORS支持全部類型的HTTP請求,功能完善。(這點JSONP被玩虐,但大部分狀況下GET已經能知足需求了)
  3. JSONP的錯誤處理機制並不完善,咱們沒辦法進行錯誤處理;而CORS能夠經過onerror事件監聽錯誤,而且瀏覽器控制檯會看到報錯信息,利於排查。
  4. JSONP只會發一次請求;而對於複雜請求,CORS會發兩次請求
  5. 始終以爲安全性這個東西是相對的,沒有絕對的安全,也作不到絕對的安全。畢竟JSONP並非跨域規範,它存在很明顯的安全問題:callback參數注入和資源訪問受權設置。CORS好歹也算是個跨域規範,在資源訪問受權方面進行了限制(Access-Control-Allow-Origin),並且標準瀏覽器都作了安全限制,好比拒絕手動設置origin字段,相對來講是安全了一點。
    可是回過頭來看一下,就算是不安全的JSONP,咱們依然能夠在服務端端進行一些權限的限制,服務端和客戶端也都依然能夠作一些注入的安全處理,哪怕被攻克,它也只能讀一些東西。就算是比較安全的CORS,一樣能夠在服務端設置出現漏洞或者不在瀏覽器的跨域限制環境下進行攻擊,並且它不只能夠讀,還能夠寫。

3.3. react經過webpack配置代理實現跨域請求:

  代理的話其實也可使用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解決跨域問題

相關文章
相關標籤/搜索