關於跨域請求的另一種解決思路

●問題產生

最近筆者遇到一個項目,描述如下:對方給我們提供了一個Url,可以通過get請求返回一串字符串作爲token,我們拿到這個token後,將作爲其中一個參數,和其他參數一起組裝成數據,在我們自己頁面上點擊按鈕,通過ajax的post請求提交給我們自己的後臺進行業務邏輯處理。

筆者首先通過瀏覽器直接訪問這個Url,驗證了確實可以拿到字符串token,因此,決定採用如下思路進行開發:第1步,頁面點擊按鈕,觸發點擊事件,通過ajax的get請求拿到字符串token,其中返回的dataType設置爲text類型;第2步,在其success對應的回調函數中,通過ajax的post請求將這個token作爲參數一起組織成數據,提交給我們的後臺。

$("#xxBtn").on("click",function(){
    //第一步,Get請求
    $.ajax({
        type:"GET",
        url : getRequestUrl,
        dataType :'text',
        success:function(response){
            //第二步,Post請求
            $.ajax({
                type:"POST",
                url : postRequestUrl,
                dataType :'json',
                data{
                    user:postuser,
                    name:postname,
                    token:response
                },
                success:function(response){
                    console.log(response.msg);
                }
            });
        }
    });
});

然而,詭異的事情出現了,通過瀏覽器F12查看確實發起了Get請求,並且狀態碼200,也有響應數據,但頁面上死活不進入success的回調函數。後來經過查詢知道,原來是跨域請求惹的禍。

解釋一下什麼是跨域請求通常,我們開發的前端頁面,發起的請求,無論是Get、Post、Put還是什麼,其請求的Url大都是自己的系統,即同一個工程中。而上述例子中,請求的Url確是對方提供的系統,不屬於我們自己的。基於安全因素的設計,前端Ajax做這種跨域請求時,網上提供兩大類解決思路,分別對應於我們開發的前端以及對方的後端。其中最常見的是網上一搜“跨域請求”時幾乎都有的方法(同質化太嚴重,都是互相copy的……),將返回類型dataType寫爲"jsonp",但是上述項目中卻不適應,原因在於其返回的壓根就不是Json對象,只是單純的一個字符串,該方法淘汰。另一類是說讓對方的系統設置運行跨域請求,添加我們請求源的Ip爲信任地址,但該方法依然不適用,對方並不提供支持。這麼看來似乎無解了,網上也查不到更多有效信息。

●問題解決

後來,和小夥伴討論了一番,想到了另外一種解決思路,將第一步的Get請求,交給我們自己的後端去完成,拿到響應token後,直接和其他參數在後臺一同處理。

首先驗證了Java後端去做Get請求時是否會出現跨域問題,發現確實並不會出現前端那樣的跨域請求問題,請求的代碼如下:

public String sendGet(String url) {
    String result = "";
    BufferedReader in = null;
    try {
        URL realUrl = new URL(url);
        URLConnection connection = realUrl.openConnection();
        // 設置通用的請求屬性
        connection.setRequestProperty("accept", "*/*");
        connection.setRequestProperty("connection", "Keep-Alive");
        connection.setRequestProperty("user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        // 建立實際連接
        connection.connect();
        // 定義 BufferedReader輸入流來讀取URL的響應
        in = new BufferedReader(new InputStreamReader(
                connection.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            result += line;
        }
    } catch (Exception e) {
        System.out.println("發送GET請求出現異常!" + e);
        e.printStackTrace();
    }
    // 使用finally塊關閉輸入流
    finally {
        try {
            if (in != null) {
                in.close();
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }
    return result;
}

相應地,前端的代碼就修改成如下:

$("#xxBtn").on("click",function(){
    //直接向後端發Post請求,數據不帶token,token由後端去Get請求獲取
    $.ajax({
        type:"POST",
        url : postRequestUrl,
        dataType :'json',
        data{
            user:postuser,
            name:postname,
            token:response
            },
        success:function(response){
            console.log(response.msg);
        }
    });
});

最後,就是配置Struts或SpringMVC相關xml,接收前端請求,進行處理,返回前端的過程了,該部分涉及工作具體內容,就不舉例了,大家可以結合自己的實際業務去編寫代碼。

●問題反思

確實,通過這種方式,能夠解決跨域請求的問題。一方面提醒了我們遇到問題,可能會有不同的解決途徑,需要勤加思索;另一方面也給我們敲了警鐘,如果是前後端分離開發的項目,無法獲得後端支持,前端真的就無解了嗎?後來筆者繼續學習,發現還是有不少解決思路的,例如通過代理等方式。今天,你學會了嗎?

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