Ajax不能跨域訪問的解決方案



 
文章介紹

這是一篇,引導文吧... 因為寫這篇文章時,實在想不出該如何分序。因此以實現跨域訪問為目的,從基礎知識往上寫。最后以百度搜索智能提示為例,來講解跨域的具體應用!

內容

首先,我們得明確什么是跨域,這里先了解一下url中各組成部分
以百度為例:

https://www.baidu.com:80

協議:https://
二級域名:www
一級域名:baidu.com


端口號:80

以上4個有一個不同即為跨域訪問,比如你當前頁面在https://www.baidu.com:80,你去用Ajax請求https://tieba.baidu.com:80的數據,就相當於跨域訪問!

在Ajax中,是不支持跨域訪問的,所以www.baidu.com拿不到tieba.baidu.com上的數據。

那么這里就要用到跨域訪問的技巧,雖然Ajax不支持,但我們可以利用src這個屬性達到目的。

對於src這個屬性,相信很多人都會想到img標簽!我們都知道img標簽的src如果設置為一個網絡地址時,那么就會去使用該網絡地址的圖片資源。

比如src=https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png

那么img標簽就會請求該url的數據返回來,其實這就已經是跨域訪問了。因為你當前的頁面並不在https://ss0.bdstatic.com上,但你卻成功訪問到了它的資源。

因此我們可以利用src這個利器,達到我們跨域訪問的目的。

不過使用src之前,得先了解一下Ajax利用請求回來的響應數據執行回調的一種方法:

//先定義一個函數,等會利用該函數執行回調 function fun (obj) { console.log(obj); } //以下均為ajax請求,粗略看即可 var url = 'test.php';//訪問當前目錄的php文件 var xhr = new XMLHttpRequest(); xhr.open('get',url); xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status >=200 && xhr.status <300 || xhr.status == 304) { //請求成功后,拿到返回字符串並使用eval執行 eval(xhr.responseText); } else { console.log('請求失敗'); } } }

為了拿到請求數據,下面我們利用php簡單制作一個后端接口test.php

<?php //創建一個php對象 name:kevin,age:23 $obj = array("name"=>"Kevin","age"=>"23"); //將php對象編碼為json格式的字符串 $json = json_encode($obj); //后端給客戶端返回一個字符串 點為字符串拼接(相當於js中加號) echo("fun(" . $json . ")");

請求成功后eval(xhr.responseText);這一句可以一步步分解為如下代碼:

  1. eval(xhr.responseText);
  2. eval(fun({"name":"Kevin", "age":"23"}));
  3. fun({"name":"Kevin", "age":"23"});
  4. console.log({"name":"Kevin", "age":"23"})

因此控制台打印如下:


瀏覽器控制台

以上我們實現了:根據后端返回的數據來決定具體執行某一個函數,並且利用請求回來的數據傳參!

但是以上並沒有解決我們跨域需求,因為我請求的后端接口,依然在當前域!

那么我剛才說了,利用src,我們就能實現跨域。假如我們使用img標簽,使其src="test.php"。這樣我們雖然拿到了數據,但是img標簽並不會像eval函數一樣幫我們執行數據,這樣數據就得不到利用。

所以對於實現跨域,我們有這樣的需求:

  1. 有src屬性
  2. 可以像eval函數一樣將數據執行!

滿足以上條件的確實有,那就是script標簽。

平時我們在script標簽內寫代碼,其實寫的就是字符串,並且script標簽會幫我們執行。

並且我們平時經常會用到script標簽的src屬性,比如引入框架時,下面以jQuery為例:
<script src="./jquery.js"></script>

其實它就相當於執行了如下:

<script>
    //一大堆jQ代碼字符串... </script>

因此我們可以利用script標簽就行跨域訪問,這里以百度為例:

這是百度搜索時,搜索提示的數據接口

https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=關鍵字&cb=方法名

比如我搜索a,頁面如下:


百度搜索提示

那么我利用接口url也會得到上面數據,如圖:


接口獲取的數據

這里方法名會根據我們的參數返回,因此你請求數據成功后要執行什么函數,那么就往cb傳該函數的方法名!

下面我用盡量少的代碼實現一下 百度搜索提示

<body>
//搜索框
<input type="text" id="input">
//數據請求回來后,往里面添加li
<ul id="ul"></ul>

<script>

//回調方法,數據返回后觸發
    function callBack(obj) {
        //從上面圖知道關鍵字數組位於數據的s屬性中
        var array = obj.s;
        //每次觸發先清空以前數據,再添加
        ul.innerHTML = "";
        for (var i = 0; i < array.length; i++) {
            var li = document.createElement('li');
            li.innerText = array[i];
            ul.appendChild(li);
        }
    }

    //url1 和 url2 為了以后方便拼接
    var url1 = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=';
    var url2 = '&cb=';
    var ul = document.getElementById('ul');
    var input = document.getElementById('input');
    //監聽輸出框的鍵盤輸入
    input.onkeyup = function () {
    //創建script標簽
        var script = document.createElement('script');
        //把輸入框的值和方法名作為url參數
        script.src = url1 + this.value+ url2 + callBack.name;
        //把script標簽添加到body,那么就會執行代碼
        document.body.appendChild(script);
        };
</script>
</body>

最后實現效果如下:


效果

代碼僅以實現效果為目的,寫得很簡短,大家可以直接拷貝到自己電腦嘗試~

 

話題到這里就結束了,web前端學習的可以來我的群,群里每天都有對應資料學習:250777811,歡迎初學和進階中的小伙伴。

如果想看到更加系統的文章和學習方法經驗可以關注的微信號:‘web前端EDU’或者‘webxh5’關注后回復‘2017’可以領取一套完整的學習視頻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM