使用vue-axios和vue-resource解決vue中呼叫網易雲介面跨域的問題

iMax發表於2018-01-17

1. 新建vue專案

1.1 新建專案

新建專案

vue init webpack axios_resource

然後具體設定如下

設定

專案名稱,專案描述,作者,Runtime + Compiler 回車即可

注意這裡要安裝vue-router和ESLint

然後Setup unit tests with Karma + Mocha?Setup e2e tests with Nightwatch?都選擇n即可

1.2 安裝專案依賴

cnpm install

依賴

1.3 安裝axios模組

cnpm install axios --save

1.4 安裝resource模組

cnpm install vue-resource --save

1.5 執行專案

cnpm run dev

效果圖如下

效果圖

1.6 修改頁面內容

我們先修改一下頁面內容 src\components\Hello.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>{{ author }}</h2>
  </div>
</template>

<script>
export default {
  name: 'hello',
  data () {
    return {
      msg: 'vue呼叫網易雲介面',
      author: '泥猴啊'
    }
  }
}
</script>
複製程式碼

效果圖如下

效果圖2

2. 使用axios

2.1 我們先修改一下頁面,讓頁面載入一些動態內容

模板修改如下

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>{{ author }}</h2>
    <ul v-for="music in musics">
    <li>
        {{ music.name }}
    </li>
    </ul>
  </div>
</template>
複製程式碼

js部分修改如下

<script>
export default {
  name: 'hello',
  data () {
    return {
      msg: 'vue呼叫網易雲介面',
      author: '泥猴啊',
      musics: []
    }
  },
  mounted: function () {
    axios.get('http://music.163.com/api/playlist/detail?id=19723756')
    .then(function (res) {
      console.log(res)
    }, function (error) {
      console.log(error)
    })
  }

}
</script>
複製程式碼

然後儲存

發現頁面有一個報錯 http://eslint.org/docs/rules/no-undef 'axios' is not defined

未定義報錯

axios沒有定義,是因為我們沒有匯入axios模組的原因

我們在js部分頂部匯入一下axios模組

import axios from 'axios'

載入axios模組之後錯誤提示消失了。 開啟除錯頁面console介面 發現有一個報錯

No 'Access-Control-Allow-Origin' header is present on the requested resource.Origin 'http://localhost:8080' is therefore not allowed access.
複製程式碼

跨域報錯

這裡的not allowed access就是提示我們瀏覽器不支援跨域請求,搜尋了很多資料,網易雲不支援跨域請求的(網易雲的伺服器在返回你的請求中沒有Access-Control-Allow-Origin這個head欄位)。

那怎麼辦呢? 那我們只能使用代理了。

下面將介紹3種代理方式:1,遠端代理 2,php代理 3,node代理

3 代理

3.1 遠端代理

就是利用別人寫好的代理介面,代理髮送你的請求,這樣就不會跨域了。

首先我們定義一個常量API_PROXY

const API_PROXY = 'https://bird.ioliu.cn/v1/?url='

然後在axios請求裡面拼接一下字串

axios.get(API_PROXY + 'http://music.163.com/api/playlist/detail?id=19723756')
複製程式碼

js 完整程式碼如下

<script>
const API_PROXY = 'https://bird.ioliu.cn/v1/?url='
import axios from 'axios'
export default {
  name: 'hello',
  data () {
    return {
      msg: 'vue呼叫網易雲介面',
      author: '泥猴啊',
      musics: []
    }
  },
  mounted: function () {
    axios.get(API_PROXY + 'http://music.163.com/api/playlist/detail?id=19723756')
    .then(function (res) {
      console.log(res)
    }, function (error) {
      console.log(error)
    })
  }
}
</script>
複製程式碼

開啟瀏覽器console介面

Object {data: Object, status: 200, statusText: "OK", headers: Object, config: Object…}config: Objectdata: Objectheaders: Objectrequest: XMLHttpRequeststatus: 200statusText: "OK"__proto__: Object
複製程式碼

請求成功

賦值給musics

this.musics = res.data.result.tracks
複製程式碼

發現頁面有個報錯

Uncaught (in promise) TypeError: Cannot set property 'musics' of undefined
複製程式碼

musics沒有定義 因為這裡,this的指向不是當前的vue例項 那我們在使用axios之前重新,定義一下this

var _this = this
複製程式碼

axios使用_this就好了

mounted部分程式碼

  mounted: function () {
    var _this = this
    axios.get(API_PROXY + 'http://music.163.com/api/playlist/detail?id=19723756')
    .then(function (res) {
      _this.musics = res.data.result.tracks
      console.log(_this.musics)
    }, function (error) {
      console.log(error)
    })
  }
複製程式碼

再開啟控制檯,發現沒有報錯,請求的資料也是我們想要的

請求成功1

再次修改一下模板

我們再增加圖片資料

修改好的模板如下

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>{{ author }}</h2>
    <ul v-for="music in musics">
      <li>
        {{ music.name }}
      </li><br>
      <li>
        <img :src="music.album.picUrl" style="width:200px;">
      </li>
    </ul>
  </div>
</template>
複製程式碼

完整程式碼如下

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>{{ author }}</h2>
    <ul v-for="music in musics">
      <li>
        {{ music.name }}
      </li><br>
      <li>
        <img :src="music.album.picUrl" style="width:200px;">
      </li>
    </ul>
  </div>
</template>

<script>
const API_PROXY = 'https://bird.ioliu.cn/v1/?url='
import axios from 'axios'
export default {
  name: 'hello',
  data () {
    return {
      msg: 'vue呼叫網易雲介面',
      author: '泥猴啊',
      musics: []
    }
  },
  mounted: function () {
    var _this = this
    axios.get(API_PROXY + 'http://music.163.com/api/playlist/detail?id=19723756')
    .then(function (res) {
      _this.musics = res.data.result.tracks
      console.log(_this.musics)
    }, function (error) {
      console.log(error)
    })
  }
}
</script>
複製程式碼

最後效果圖如下

最後效果圖


3.2 php用curl代理

這裡演示vue-resource的寫法 + php curl 完成代理請求

前面我們安裝了vue-resource模組,我們要在main.js載入一下vue-resource模組

載入

import VueResource from 'vue-resource'

使用

Vue.use(VueResource)

為了避免和之前頁面混淆,我們重新新增一個curl頁面,路由同樣新增加一條'/curl'的路由

index.js 完整程式碼如下

import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import Curl from '@/components/Curl'
import VueResource from 'vue-resource'

Vue.use(Router)
Vue.use(VueResource)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: Hello
    },
    {
      path: '/curl',
      name: 'Curl',
      component: Curl
    }
  ]
})
複製程式碼

其實vue-resourceget方法基本上和axios很像,基本上沒有太多變動

  mounted: function () {
    this.$http.get('http://localhost/curl.php', {}, {
      headers: {

      },
      emulateJSON: true
    }).then(function (res) {
      this.musics = res.data.result.tracks
      console.log(this.musics)
    }, function (error) {
      console.log(error)
    })
  }
複製程式碼

headers get方法裡面不用填寫引數,如果是post方式傳送請求 則要設定Access-Control-Allow-Origin: *

完整程式碼如下 src\components\Curl.vue

<template>
  <div class="curl">
    <h1>{{ msg }}</h1>
    <h2>{{ author }}</h2>
    <ul v-for="music in musics">
      <li>
        {{ music.name }}
      </li><br>
      <li>
        <img :src="music.album.picUrl" style="width:200px;">
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'curl',
  data () {
    return {
      msg: 'vue呼叫網易雲介面',
      author: '泥猴啊',
      musics: []
    }
  },
  mounted: function () {
    this.$http.get('http://localhost/curl.php', {}, {
      headers: {

      },
      emulateJSON: true
    }).then(function (res) {
      this.musics = res.data.result.tracks
      console.log(this.musics)
    }, function (error) {
      console.log(error)
    })
  }
}
</script>
複製程式碼

當然了,最重要的是curl.php這個部分程式碼怎麼寫了 curl.php 完整程式碼

<?php
// header('Content-type:text/html;Charset=utf-8'); 
header('Content-Type:text/json;charset=utf-8');//設定返回檔案的型別
header('Access-Control-Allow-Origin: *');//設定允許所有跨域
$id = '19723756';       //id   
$va_url = 'http://music.163.com/api/playlist/detail?';            //驗證的 url 連結地址
$post_fields = "id={$id}"; //post提交資訊串  
$curl = curl_init(); //初始化一個cURL會話,必有  
//curl_setopt()函式用於設定 curl 的引數,其功能非常強大,具體看手冊  
curl_setopt($curl, CURLOPT_URL, $va_url);      //設定驗證登陸的 url 連結  
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //設定結果儲存在變數中,還是輸出,預設為0(輸出)  
curl_setopt($curl, CURLOPT_POST, 1);           //模擬post提交  
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_fields); //設定post串
//避免https請求報錯 Curl error: SSL certificate problem: unable to get local issuer certificate
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

$data = curl_exec($curl);  //執行此cURL會話,必有  
// echo "<pre>";
// print_r(json_decode($data));
echo $data;
//檢查是否有錯誤  
if(curl_errno($curl)) {  
    exit('Curl error: ' . curl_error($curl));  
}  

curl_close($curl);         //關閉會話 
複製程式碼

curl請求的話就解釋了,大家可以去看手冊 最重要的是設定標頭檔案允許跨域

header('Access-Control-Allow-Origin: *');
複製程式碼

如果沒有設定這個的話,代理也是沒有意思的,不然前端還是會提示跨域

當然啦,你要把curl.php這個檔案丟在你apache或者nginx根目錄,同時apache或者nginx伺服器也別忘記啟用了哦。

請求成功2

3.3 nodejs代理

同樣的我們新建一個Node.vue的模板和/node的路由

    {
      path: '/node',
      name: 'Node',
      component: Node
    }
複製程式碼

index.js 完整程式碼

import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import Curl from '@/components/Curl'
import Node from '@/components/Node'
import VueResource from 'vue-resource'

Vue.use(Router)
Vue.use(VueResource)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: Hello
    },
    {
      path: '/curl',
      name: 'Curl',
      component: Curl
    },
    {
      path: '/node',
      name: 'Node',
      component: Node
    }
  ]
})
複製程式碼

設定代理

開啟config/index.js 修改proxyTable: {}部分 修改為

    proxyTable: {
      '/api': {
        target: 'http://music.163.com/api',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
複製程式碼

第一行的'/api'指的是虛擬路徑 target指的是目標地址,也就是實際api的地址 pathRewrite規則重寫

然後在內碼表面修改一下請求地址

  mounted: function () {
    this.$http.get('/api/playlist/detail?id=19723756', {}, {
      headers: {

      },
      emulateJSON: true
    }).then(function (res) {
      this.musics = res.data.result.tracks
      console.log(this.musics)
    }, function (error) {
      console.log(error)
    })
  }
複製程式碼

/api/playlist/detail?id=19723756上面的這個地址其實就等於http://localhost:8080/api+/playlist/detail?id=19723756

注意這裡一定要重啟一下node,因為你修改了node的配置一定要重啟才能生效

在命令符視窗ctrl + c 然後重新執行cnpm run dev 這時候,命令視窗會提示

[HPM] Proxy created: /api  ->  http://music.163.com/api
[HPM] Proxy rewrite rule created: "^/api" ~> ""
> Starting dev server...
複製程式碼

說明代理成功

代理成功

然後訪問http://localhost:8080/#/node

請求成功3

就能看到效果了 完整程式碼 src\components\Node.vue

<template>
  <div class="curl">
    <h1>{{ msg }}</h1>
    <h2>{{ author }}</h2>
    <ul v-for="music in musics">
      <li>
        {{ music.name }}
      </li><br>
      <li>
        <img :src="music.album.picUrl" style="width:200px;">
      </li>
    </ul>
  </div>
</template>
複製程式碼
<script>
export default {
  name: 'curl',
  data () {
    return {
      msg: 'vue呼叫網易雲介面',
      author: '泥猴啊',
      musics: []
    }
  },
  mounted: function () {
    this.$http.get('/api/playlist/detail?id=19723756', {}, {
      headers: {

      },
      emulateJSON: true
    }).then(function (res) {
      this.musics = res.data.result.tracks
      console.log(this.musics)
    }, function (error) {
      console.log(error)
    })
  }
}
</script>
複製程式碼

github地址 github.com/pandoraxm/v…

原文連結 www.bear777.com/blog/vue-vu…

相關文章