• 【Vue】学习笔记-Vue中的Ajax配置代理


    回顾

    常用的发送Ajax请求的方法有哪些?

    • xhr​​ new XMLHttpRequest() xhr.open()、xhr.send()(真正开发中很少用到,太麻烦了,我们一般使用的都是他的二次封装) ​
    • jQuery​​ 其对xhr有二次封装 . g e t ( ) 、 .get()、 .get().post ​​axios​​ Promise风格,体积比jQuery小,并且支持请求拦截器、响应拦截器等等(最常用,也是Vue推荐的发送Ajax请求的方法)
    • ​​fetch​​ 跟xhr是平级的,它在window内置对象上直接存在!并且其也是Promise风格的,IE不支持(也有人使用)

    尝试使用axios发送Ajax请求

    假设现在已经开好了两台服务器
    在本机的5000端口,使用get请求我们可以获取学生信息
    在这里插入图片描述
    我们在页面上创建一个按钮,点击即可发送get请求获的学生数据:

    <template>
    	<div>
    		<button @click="getStudents">获取学生信息</button>
    		<button @click="getCars">获取汽车信息</button>
    	</div>
    </template>
    
    <script>
    	import axios from 'axios'
    	export default {
    		name:'App',
    		methods: {
    			getStudents(){
    				axios.get('http://localhost:5000/students').then(
    					response => {
    						console.log('请求成功了',response.data)
    					},
    					error => {
    						console.log('请求失败了',error.message)
    					}
    				)
    			},
    			getCars(){
    				axios.get('http://localhost:5000/demo/cars').then(
    					response => {
    						console.log('请求成功了',response.data)
    					},
    					error => {
    						console.log('请求失败了',error.message)
    					}
    				)
    			}
    		},
    	}
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在这里插入图片描述
    很明显这是一个跨域问题,也就是说我们违背了​​同源策略​​

    复习:同源策略规定了三个东西必须一致
    ①协议名
    ②主机名
    ③端口号

    我们现在所处的位置是localhost:8080

    也就是说此时我们所处的状态:
    使用的http协议
    主机名是localhost
    端口号是8080

    但服务器所处的状态:
    使用的http协议
    主机名是localhost
    端口号是5000
    在这里插入图片描述
    所以说并不同源,故发生了跨域问题

    跨域问题的过程:浏览器发出请求之后,服务器接收到了请求。​​同时服务器也会把数据交给本地浏览器​​​。​​浏览器也收到了这个数据​​,但是浏览器发现这里存在跨域问题,所以浏览器不会把这个数据交给用户!

    那么我们如何解决跨域问题呢?
    这里有几种思路:

    • ​​cors​​ 最标准的解决办法 使用这个方法不用前端人员去做任何事情。其原理是:写服务器的人,让服务器给我们返回数据的时候加几个响应头,而浏览器看到了这几个响应头,就会放行,把数据给我们。
    • ​​jsonp​​ 借助script标签的src属性。(真正开发基本不用!,因为其需要前后端一起配合,并且只能解决get请求的跨域问题)

    使用代理服务器解决跨域问题的原理

    在这里插入图片描述
    左边红色方框代表本地浏览器,中间的粉色方框代表代理服务器,右边的蓝色方框代表服务器。

    左边这个8080服务器,是Vue脚手架帮我们开启的,用来支撑脚手架的运行

    这个代理服务器与我们所处的端口号一定是一样的!

    当我们向服务器请求学生信息的时候,我们不直接请求服务器,而是找代理服务器,代理服务器收到了我们本次请求之后,他会帮我们把请求转发给服务器。然后服务器会把数据交给代理服务器,最后代理服务器再把数据交给我们。

    从这个过程中我们不难看出,代理服务器有点“中介”的味道
    在这里插入图片描述
    有人可能会问这两条线难道不会存在跨域问题吗?
    当然不会
    !左边的是代理服务器,右边的是服务器。服务器与服务器之间传数据压根就不用Ajax,Ajax它是一种前端技术!

    Vue脚手架配置代理

    既然我们知道了要用代理服务器来解决跨域问题,那么我们怎么开启这个服务器呢?
    这里有两种常用的方法:

    ​​nginx​​
    ​​vue-cli​​ (也就是借助Vue脚手架)
    这里我们使用第二种方式,他更加的简单。

    方法一
    打开Vue-CLI的配置参考,找到devServer.proxy
    devServer.proxy

    在这里插入图片描述
    注意:这个proxy配置项里面填的是代理服务器向哪一个服务器拿东西

    根据上面的案例(向5000端口的服务器要学生数据),代码如下:

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
      transpileDependencies: true,
       devServer:{
        proxy:'http://localhost:5000'
      }, 
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    因为我们修改了Vue的配置文件,所以必须重启脚手架才能生效、

    在这个基础上我们修改请求的服务器:
    src\App.vue

    <template>
    	<div>
    		<button @click="getStudents">获取学生信息</button>
    		<button @click="getCars">获取汽车信息</button>
    	</div>
    </template>
    
    <script>
    	import axios from 'axios'
    	export default {
    		name:'App',
    		methods: {
    			getStudents(){
    				axios.get('http://localhost:8080/students').then(
    					response => {
    						console.log('请求成功了',response.data)
    					},
    					error => {
    						console.log('请求失败了',error.message)
    					}
    				)
    			},
    			getCars(){
    				axios.get('http://localhost:5000/demo/cars').then(
    					response => {
    						console.log('请求成功了',response.data)
    					},
    					error => {
    						console.log('请求失败了',error.message)
    					}
    				)
    			}
    		},
    	}
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在这里插入图片描述
    这里有两个细节需要我们注意:

    ①这样配置代理服务器并非会把所有请求发给服务器。
    当我们请求的资源8080服务器(本地服务器)本来就有的时候,代理服务器不会再把请求转发给服务器.
    我们脚手架中的public文件夹就相当于8080服务器(本地服务器)的根路径。说直白点8080服务器中有什么public文件夹中就有什么。

    我们可以举一个例子:
    在这里插入图片描述
    我们在students文件中写上112233。如果在这种情况下我们去请求,代理服务器不会把请求转发,而是直接返回112233.
    在这里插入图片描述
    ②使用这种方式配置,只能配置一个代理服务器!
    在这里插入图片描述
    本例需要下载axios库 npm install axios
    配置参考文档Vue-Cli devServer.proxy
    vue.config.js 是一个可选的配置文件,如果项目的(和package.json同级的)根目录中存在这个文件,那么它会被@vue/cli-service 自动加载。你也可以使用package.json中的vue字段,但是注意这种写法需要你严格遵照JSON的格式来写
    方法一
    在vue.config.js中添加如下配置

    devServer:{
      proxy:"http://localhost:5000"
    }
    
    • 1
    • 2
    • 3

    说明:

    1. 优点:配置简单,请求资源时直接发给前端(8080)即可。
    2. 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
    3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

    方法二
    编写vue.config.js配置具体代理规则:

    module.exports = {
    	devServer: {
          proxy: {
          '/api1': {// 匹配所有以 '/api1'开头的请求路径
            target: 'http://localhost:5000',// 代理目标的基础路径
            changeOrigin: true,
            pathRewrite: {'^/api1': ''}//重写路径。也就是把/api1给替换为空格。否则会把/api1也放在url里带给服务器
          },
          '/api2': {// 匹配所有以 '/api2'开头的请求路径
            target: 'http://localhost:5001',// 代理目标的基础路径
            changeOrigin: true,
            pathRewrite: {'^/api2': ''}
          }
        }
      }
    }
    /*
       changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
       changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
       changeOrigin默认值为true
    */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    说明:

    配置好后在访问目标服务器资源时。就要在端口后后面加/api1前缀。表示走代理服务器。不加表示不走代理。当然/api1可以换个名字。比如:/fhzm

    1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
    2. 缺点:配置略微繁琐,请求资源时必须加前缀。

    如果不重写路径:
    在这里插入图片描述

    代理服务器在转发请求的时候,也会带上前缀。也就是说代理服务器是想要服务器上的​​/api1/students​​​数据,但我们的本意是要​​/students​​的数据。

    解决这个问题我们需要另外一个配置项:​​pathRewrite​​
    它的值是一个对象,里面包含着key和value。其中key写正则的匹配条件,value是替换的值

    2、GitHub用户搜索案例
    public\index.html

    DOCTYPE html>
    <html lang="">
      <head>
        <meta charset="utf-8">
        
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
         
        <link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">
        <title><%= htmlWebpackPlugin.options.title %>title>
      head>
      <body>
        
        <noscript>
          <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
        noscript>
        
        <div id="app">div>
        
      body>
    html>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    src\App.vue

    <template>
            <div class="container">
                <Search/>
                <List/>
            </div>  
    </template>
    
    <script>
    import Search from "./components/Search.vue";
    import List from "./components/List.vue"
    
        export default {
            name:"App",
            components:{ 
                Search,
                List
            },
            data(){
                return{
                }
            }
        }
    
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    src\components\List.vue

    <template>
        <div class="row">
            <!-- 展示用户列表 -->
            <div v-show="info.users.length" class="card" v-for="u in info.users" :key="u.login">
                <a :href="u.html_url" target="_blank">
                <img :src="u.avatar_url" style='width: 100px'/>
                </a>
                <p class="card-text">{{u.login}}</p>
            </div>
            <!-- 展示欢迎词 -->
            <h1 v-show="info.isFirst">欢迎使用</h1>
    
            <!-- 展示加载 -->
            <h1 v-show="info.isLoading">加载中。。。。。</h1>
    
            <!-- 展示错误信息 -->
            <h1 v-show="info.errMsg">{{info.errMsg}}</h1>
        </div>
        
    </template>
    
    <script>
        export default{
            name:"List",
            data(){
                return{
                    info:{
                        isFirst:true,
                        isLoading:false,
                        errMsg:"",
                        users:[]
                    }
                }
            },
            methods:{
                allUsers(obj){
                    this.info={...this.info,...obj};
                }
    
            },
            
            mounted(){
                this.$bus.$on("updateListData",this.allUsers);
            }
        }
    
    </script>
    
    <style scoped>
        .album {
        min-height: 50rem; /* Can be removed; just added for demo purposes */
        padding-top: 3rem;
        padding-bottom: 3rem;
        background-color: #f7f7f7;
        }
    
        .card {
        float: left;
        width: 33.333%;
        padding: .75rem;
        margin-bottom: 2rem;
        border: 1px solid #efefef;
        text-align: center;
        }
    
        .card > img {
        margin-bottom: .75rem;
        border-radius: 100px;
        }
    
        .card-text {
        font-size: 85%;
        }
    
    </style>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    src\components\Search.vue

    <template>
        <section class="jumbotron">
            <h3 class="jumbotron-heading">Search Github Users</h3>
            <div>
                <input type="text" v-model="keyWord" placeholder="enter the name you search"/>&nbsp;
                <button @click="searchUsers">Search</button>
            </div>
        </section>
      
    </template>
    
    <script>
    
        import axios from "axios";
        //https://api.github.com/search/users?q=xxx
        export default{
            name:"Search",
            data(){
                return{
                    keyWord:""
                }
            },
            methods:{
                searchUsers(){
    
                     this.$bus.$emit("updateListData",{isFirst:false,isLoading:true, errMsg:"",users:[]})
    
                    axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
                    response=>{
                      
                         this.$bus.$emit("updateListData",{isLoading:false, errMsg:"",users:response.data.items})
                    },reason=>{
                          this.$bus.$emit("updateListData",{isLoading:false, errMsg:reason.message,users:[]})
                    });
                },
            },
        }
    </script>
    
    <style>
    
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

  • 相关阅读:
    html一个案例学会所有常用HTML(H5)标签
    国内网络编译,Ambari 2.7.6 全部模块源码编译笔记
    Java 程序猿看完这些面试题,想斩获 BAT 的 offer 都很难!
    设计模式之桥接模式
    3DMax
    c++ 关于引用变量你不知道的东西
    连接全球金融网络 探索SCF公链的多元价值
    2022 第297周周赛
    sklearn实现决策树,随机森林,逻辑回归,KNN,贝叶斯,SVM,以葡萄干数据集为例
    SpringSecurity系列——会话管理,CSRFday8-1(源于官网5.7.2版本)
  • 原文地址:https://blog.csdn.net/david_520042/article/details/130900337