js跨域問題的三種解決方案

概述

跨域問題在分佈式應用中經常會遇到,這裏僅僅介紹跨域的三種解決方案,對跨域的概念及原因不做解釋,感興趣的朋友可以網上自行百度。

Nginx代理

這種方式比較簡單,將A應用和B應用都通過一個統一的地址進行轉發,這樣就可以避免跨域問題出現。

server {
        listen       80;
        server_name  www.gameloft9.top;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }
location /manager {
            proxy_pass http://127.0.0.1:6108/manager;
            proxy_set_header Host $http_host;
        }
location /service {
            proxy_pass http://127.0.0.1:9200/service;
            proxy_set_header Host $http_host;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
		}

在上面的配置中,manager和service屬於不同的域(IP雖然一樣,但是端口不一樣),如果manger裏面的js調用service裏面的接口,會報跨域錯誤。通過nginx轉發後,所有的域都映射到www.gameloft9.top了,然後通過/manager,/service分別轉發到各自的應用中,巧妙的避免了跨域問題。如果是純前端項目,可以直接託管到nginx裏面,也可以解決跨域問題,原理一樣。

JSONP

因爲<script>標籤不受跨域限制,因此在此基礎上出現了JSONP的ajax請求方式。通過包裝一個<script>標籤,去請求接口,然後返回數據及回調函數,這樣就達到了跨域的目的。

/**
     * 測試JSONP跨域請求
     * */
    function testJsonP() {
        $.ajax({
            url: root + "/testjsonp.do",
            type: "GET",//jsonp只支持GET請求
            data: request,
            dataType: "jsonp",
            jsonp: "callback",//指定查詢字符串中回調方法key
            jsonpCallback: "print",//指定查詢字符串中回調方法value,例如callback=print
            success: function (data) {//返回的是回調方法的入參
                //alert(data)
            }
        })
    }

JSONP的請求方式,需要設置dataType爲"jsonp",表明這是一個jsonp的請求,jsonp是指定查詢字符串中回調函數的參數的名稱,jsonpCallback指定的是查詢字符串中回調的函數名。一個標準的jsonp的請求如下所示:

http://localhost:8080/demo/testjsonp.do?callback=print&number=2&_=1519870989148
jsonp只支持get請求,所有的參數都會轉化爲查詢字符串,然後再補上回調函數的參數(就是這裏的callback=print),如果jsonpCallback沒有指定,jQuery會自動生成一個隨機的函數名稱,例如:
Query17208297070672462461_1491991295320

當然我們不建議這麼做。

後臺處理如下:

/**
     * 測試ajax josnp跨域請求
     * */
    @RequestMapping(value = "/testjsonp.do", method = RequestMethod.GET)
    //@ResponseBody
    public void test(Model model,String callback,String number, HttpServletRequest request,HttpServletResponse response)throws Exception{
        //如果是spring mvc,啓用了@ResponseBody註解,可以直接返回調用語句
        //return callback+"("+result.toString()+")";

        Integer result = Integer.parseInt(number);
        result = result*result;//計算平方值

        Writer client = response.getWriter();
        client.write(callback+"("+result.toString()+")");
        client.flush();
    }

後臺接受到參數後,進行業務邏輯調用,並把結果塞進回調函數中,返回即可。

設置Access-Control-Allow-*頭

jsonp的方式雖然簡便,但有個缺點,就是隻支持get請求,對於只支持post的接口就不支持了。通過後臺設置Access-Control-*等header,可以解決跨域問題,而且get,post都支持。

/**
     * 測試ajax 設置head跨域請求
     * */
    @RequestMapping(value = "/testCrossOrigin.do", method = RequestMethod.POST)
    @ResponseBody
    public String crossOrigin(Model model,String number,HttpServletRequest request,HttpServletResponse response)throws Exception{

        //設置response header,允許跨域請求
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Methods","POST");
        response.setHeader("Access-Control-Allow-Headers","x-requested-with,content-type");
        response.setHeader("Access-Control-Allow-Max-Age","1728000");//單位:秒,這裏是20天

        Integer result = Integer.parseInt(number);
        result = result*result;

       return result.toString();
    }

Access-Control-Allow-Origin設置允許跨域的白名單,在白名單裏的跨域請求是允許的。

Access-Control-Allow-Methods設置接受的方法,這裏只接受POST方法。

Access-Control-Allow-Headers設置接受的請求頭,用逗號分隔。

Access-Control-Allow-Max-Age設置預檢的有效期,單位爲秒。發送正式請求前,瀏覽器會預先發送一個預檢請求,如果服務器返回了上述信息,表明是可以跨越請求的,然後纔會正式發送請求。預檢成功後,在有效期內就不用再發送了。

運行截圖

工程地址:https://github.com/gameloft9/cors-demo

參考文章:1-跨域資源共享CORS詳解

                2-cors

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章