zoukankan      html  css  js  c++  java
  • vue中的跨域问题

    https://segmentfault.com/a/1190000011072725(原文)

     

    使用vue-axios和vue-resource解决vue中调用网易云接口跨域的问题

    注(api很重要,相当于拦截到api然后将api替换为index里的 target: 'http://news-at.zhihu.com/api',如果缺少了api也会报错,404,但是看出不来到底啥原因

     

    1.6 修改页面内容

    我们先修改一下页面内容 srccomponentsHello.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. 使用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="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="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: *

    完整代码如下 srccomponentsCurl.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="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

    就能看到效果了
    完整代码 srccomponentsNode.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="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>
  • 相关阅读:
    第5次系统综合实践
    第4次系统综合实践
    第3次系统综合实践
    第2次实践作业
    第1次实践作业
    第03组 Beta版本演示
    第03组 Beta冲刺(4/4)
    OO第四单元总结
    OO第三单元总结
    OO第二单元总结
  • 原文地址:https://www.cnblogs.com/dianzan/p/10570563.html
Copyright © 2011-2022 走看看