天天看點

本地web通路遠端伺服器後端引發的跨域問題

首先,說明一下案例性質,web調用restApi。

其次,說明一下案例的基本情況。我在本地編寫的web程式,後端程式儲存在遠端伺服器端,如166.66.66.6:8000/setup。

本次介紹的跨域的解決辦法,不涉及jsonp方式。而是需要将後端的代碼中設定Access-Control-Alow-Origin = “*”,表示允許一切跨域通路。Access-Control-Alow-Origin一次隻能設定一個域名,但是如果想要同時設定多個域名的話,解決辦法是,建立一個允許跨域請求的域名清單,然後擷取請求來源域名,和清單進行對比,如果來源域名存在允許的跨域請求域名清單裡面,再添加Access-Control-Alow-Origin響應頭。

第 一次出現問題的情況: $.ajax中設定url:“……”,data:{ “name”, “xiaobai”;“age”,“22” },type:“post”,則會發生報錯400,response提示{"ret":-1,"info":"Failed to parse JSON invalid character 'a' looking for beginning of value"},意思是傳送的資料沒能成功轉為JSON字元串。這時,将設定改為data:JSON.stringify{ “name”, “xiaobai”;“age”,“22” },dataType:“json”則成功。。這裡dataType是對傳回的資料進行格式的轉換。原了解釋一下,

注意,這裡出現的問題,如果web代碼和後端代碼在同一個域時,則會自動轉為JSON格式。而不需要JSON.stringify轉化。還有一點,若web代碼在本地,後端代碼在伺服器端,可以通過nginx代理,使其避開跨域問題的發生。

第二次出現問題的情況:如果隻是簡單的post發送方式,将json格式的資料發送到後端,則按照上述第一次出現的情況,即可解決問題。當需要在ajax中加入

beforeSend:function(xhr){
    xhr.setRequestHeader("Authorization", userToken);
//xhr.setRequestHeader("Content-Type", "application/json");
},      

時,又會出現報錯提示: Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. 這 個時候,問題出現在content-type出現了問題。因為我們準備的資料時string格式的,同時ajax預設送出時告訴伺服器資料格式是 "'application/x-www-form-urlencoded",當我們用JSON.stringify轉化資料後,伺服器調用相關的 Converter解析的時候發現解析不了(因為我們的數 據格式其實是json格式)。由于content-type的不正确,導緻post方法,用options方式發送過去了。故而,由于發送方式不同,後端 不能正确接收資料。 解決辦法是(背景的處理方式):

location / {
           if ($request_method = OPTIONS ) {
               add_header Access-Control-Allow-Origin  "*";
               add_header Access-Control-Allow-Methods "POST, GET, PUT, UPDATE, DELETE, OPTIONS";
               add_header Access-Control-Allow-Headers "Authorization";
               add_header Access-Control-Allow-Credentials  "true";
               add_header Content-Length 0;
               add_header Content-Type text/plain;
               return 200;
           }
location ~ ^/(join|login|logout|user)$ {
            if ($request_method = OPTIONS) {
                rewrite ^(.*)$ / last;
            }
} 
           

第三次出現問題的情況,如果用angularjs的$http發送資料,則又會提示跨域的錯誤提示,那麼添加headers:{“content-type”:“ application/x-www-form-urlencoded ”};則請求成功。

綜上,雖然問題已經解決了,而且基本确定是content-type變化導緻的問題,可是我有幾點疑問沒有解決。

第一點,post變options是因為content-type的原因,可是我本地沒有設定request的content-type,後端沒有設定response的content-type,而是隻在後端設定了if ($request_method = OPTIONS) {rewrite ^(.*)$ / last;},就能解決跨域問題。這是為什麼?

第二點是,JSON.stringify使content-type預設值改變,導緻問題發生,可以隻在背景設定了Access-Control-Allow-Headers=“*”,而沒有設定request的content-type就成功了,這又是為什麼?

以上均為個人了解,有誤之處,請指正。也希望有大神幫忙解決一下我的問題~~~

http://www.cnblogs.com/taoys/archive/2010/12/30/1922186.html 講解content-type中application/x-www-form-urlencoded内容;

http://fyq891014.blog.163.com/blog/static/20074019120123305029795/ 講解jquery,ajax參數的問題;

http://www.cnblogs.com/yeer/archive/2009/07/23/1529460.html 講解jquery中ajax參數問題(更詳細);

首先,說明一下案例性質,web調用restApi。

其次,說明一下案例的基本情況。我在本地編寫的web程式,後端程式儲存在遠端伺服器端,如166.66.66.6:8000/setup。

本次介紹的跨域的解決辦法,不涉及jsonp方式。而是需要将後端的代碼中設定Access-Control-Alow-Origin = “*”,表示允許一切跨域通路。Access-Control-Alow-Origin一次隻能設定一個域名,但是如果想要同時設定多個域名的話,解決辦法是,建立一個允許跨域請求的域名清單,然後擷取請求來源域名,和清單進行對比,如果來源域名存在允許的跨域請求域名清單裡面,再添加Access-Control-Alow-Origin響應頭。

第 一次出現問題的情況: $.ajax中設定url:“……”,data:{ “name”, “xiaobai”;“age”,“22” },type:“post”,則會發生報錯400,response提示{"ret":-1,"info":"Failed to parse JSON invalid character 'a' looking for beginning of value"},意思是傳送的資料沒能成功轉為JSON字元串。這時,将設定改為data:JSON.stringify{ “name”, “xiaobai”;“age”,“22” },dataType:“json”則成功。。這裡dataType是對傳回的資料進行格式的轉換。原了解釋一下,

注意,這裡出現的問題,如果web代碼和後端代碼在同一個域時,則會自動轉為JSON格式。而不需要JSON.stringify轉化。還有一點,若web代碼在本地,後端代碼在伺服器端,可以通過nginx代理,使其避開跨域問題的發生。

第二次出現問題的情況:如果隻是簡單的post發送方式,将json格式的資料發送到後端,則按照上述第一次出現的情況,即可解決問題。當需要在ajax中加入

beforeSend:function(xhr){
    xhr.setRequestHeader("Authorization", userToken);
//xhr.setRequestHeader("Content-Type", "application/json");
},      

時,又會出現報錯提示: Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. 這 個時候,問題出現在content-type出現了問題。因為我們準備的資料時string格式的,同時ajax預設送出時告訴伺服器資料格式是 "'application/x-www-form-urlencoded",當我們用JSON.stringify轉化資料後,伺服器調用相關的 Converter解析的時候發現解析不了(因為我們的數 據格式其實是json格式)。由于content-type的不正确,導緻post方法,用options方式發送過去了。故而,由于發送方式不同,後端 不能正确接收資料。 解決辦法是(背景的處理方式):

location / {
           if ($request_method = OPTIONS ) {
               add_header Access-Control-Allow-Origin  "*";
               add_header Access-Control-Allow-Methods "POST, GET, PUT, UPDATE, DELETE, OPTIONS";
               add_header Access-Control-Allow-Headers "Authorization";
               add_header Access-Control-Allow-Credentials  "true";
               add_header Content-Length 0;
               add_header Content-Type text/plain;
               return 200;
           }
location ~ ^/(join|login|logout|user)$ {
            if ($request_method = OPTIONS) {
                rewrite ^(.*)$ / last;
            }
} 
           

第三次出現問題的情況,如果用angularjs的$http發送資料,則又會提示跨域的錯誤提示,那麼添加headers:{“content-type”:“ application/x-www-form-urlencoded ”};則請求成功。

綜上,雖然問題已經解決了,而且基本确定是content-type變化導緻的問題,可是我有幾點疑問沒有解決。

第一點,post變options是因為content-type的原因,可是我本地沒有設定request的content-type,後端沒有設定response的content-type,而是隻在後端設定了if ($request_method = OPTIONS) {rewrite ^(.*)$ / last;},就能解決跨域問題。這是為什麼?

第二點是,JSON.stringify使content-type預設值改變,導緻問題發生,可以隻在背景設定了Access-Control-Allow-Headers=“*”,而沒有設定request的content-type就成功了,這又是為什麼?

不确定,我寫的這些是否正确,如果疑問,歡迎指正。也希望有大神幫忙解決一下我的問題~

http://www.cnblogs.com/taoys/archive/2010/12/30/1922186.html 講解content-type中application/x-www-form-urlencoded内容;

http://fyq891014.blog.163.com/blog/static/20074019120123305029795/ 講解jquery,ajax參數的問題;

http://www.cnblogs.com/yeer/archive/2009/07/23/1529460.html 講解jquery中ajax參數問題(更詳細);

繼續閱讀