0


VUE进行前后端交互

参考文章:(8条消息) 三、vue前后端交互(轻松入门vue)_vue如何和后端交互_莫逸风的博客-CSDN博客

一、 跨域

1. 什么是跨域?

在了解什么是跨域的时候,我们首先要了解一个概念,叫同源策略,什么是同源策略呢,就是我们的浏览器出于安全考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。

2. 什么是本域?

本域指的是同协议、同端口、同域名

3. 浏览器请求的三种报错

① 请求未发送

② 请求发送后,服务器发现不一样,服务器未反应。

③ 请求发送,服务器有反应,数据返回的时候,浏览器发现不对,被拦截。

二、SpringBoot解决跨域问题+其他前后端跨域请求解决方案

1. SpringBoot上直接添加@CrossOrigin

在Controller层直接添加@CrossOrigin注解就可以解决

2. 处理跨域请求的Configuration

CrossOriginConfig.java
继承WebMvcConfigurerAdapter或者实现WebMvcConfigurer接口

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * AJAX请求跨域
 * @author Mr.W
 * @time 2018-08-13
 */
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
    static final String ORIGINS[] = new String[] { "GET", "POST", "PUT", "DELETE" };
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods(ORIGINS)
                .maxAge(3600);
    }
}

3. 采用过滤器的方式

3.1 方式一

 @Component
public class CORSFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        res.addHeader("Access-Control-Allow-Credentials", "true");
        res.addHeader("Access-Control-Allow-Origin", "*");
        res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
        if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
            response.getWriter().println("ok");
            return;
        }
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
}

3.2 方式二

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * @author JiaweiWu
 * @create 2018/3/22.
 */
@Configuration
public class RouteConfiguration {
    //这里为支持的请求头,如果有自定义的header字段请自己添加(不知道为什么不能使用*)
    private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client";
    private static final String ALLOWED_METHODS = "*";
    private static final String ALLOWED_ORIGIN = "*";
    private static final String ALLOWED_Expose = "*";
    private static final String MAX_AGE = "18000L";

    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                headers.add("Access-Control-Max-Age", MAX_AGE);
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                headers.add("Access-Control-Expose-Headers", ALLOWED_Expose);
                headers.add("Access-Control-Allow-Credentials", "true");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}
  1. ServerWebExchange的注释: ServerWebExchange是一个HTTP请求-响应交互的契约。提供对HTTP请求和响应的访问,并公开额外的服务器端处理相关属性和特性,如请求属性。

4. 其他解决方案---NGINX反向代理

server {
        listen       80;
        server_name  abc.com;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;

        location /client { #访问客户端路径
            proxy_pass http://localhost:81;
            proxy_redirect default;
        }
        location /apis { #访问服务器路径
            rewrite  ^/apis/(.*)$ /$1 break;
            proxy_pass   http://localhost:82;
       }
}

三、VUE的前后端交互

1. 前后端交互模式

1.1 传统的交互方式

原生AJAX、基于jQuery的ajax、fetch、axios

1.2 传统的URL

格式:schema://host:port/path?query#fragment

schema:协议,例如http、https、ftp等。
host:域名或者IP地址。
port:端口,http默认端口80,可以省略。
path:路径,例如/abc/a/b/c
query:查询参数,例如uname=lisi&age=12
fragment:锚点(哈希Hash),用于定位页面的某个位置

1.3RESTFUL风格的URL

HTTP请求方式

  1. GET 查询
  2. POST 添加
  3. PUT 修改
  4. DELETE 删除

2. Promise相关概念与使用

2.1 promise使用的优势

Promise是异步编程的一种解决方案,从语法上讲,Promise是一个对象,从它可以获取异步操作的消息。

  • 可以避免多层异步调用嵌套问题(回调地域)
  • Promise对象提供了简介的API,使得控制异步操作更加容易

2.2 promise的基本用法

  • 实例化Promise对象,构造函数中传递函数,该函数中用于处理异步任务。
  • resolve和reject两个(方法)参数用于处理成功和失败两种情况,并通过p.then获取处理结果。
var p = new Promise(function(resolve,reject){
    //成功时调用resolve()
    //失败时调用reject()
});
p.then(function(ret){
    //从resolve得到正常结果
},function(ret){
    //从reject得到错误信息
});

2.3 then参数的函数返回值

2.3.1 返回实例对象

p.then(function(ret){
    //返回一个实例对象,这个实例对象用于调用下一个then
    return new Promise();
}).then(...)

???在上面也就是如果目前获取了对象就相当于传到了ret中,下一步then中ret则可以调用其中的数据或者其他方法???

2.3.2 返回普通值

返回的普通值会直接传递给下一个then,通过then函数中函数的参数接收该值(底层会对返回的普通值封装为一个Promise使得能够继续调用then)

p.then(function(ret){
    
    return "hahah";
}).then(function(ret){
    alter(ret); //这里的输出值就是 hahah
}

2.3.3 基于promise请求ajax的demo

<script>
    //Promise基本使用,原生ajax
    function getText(url) {
        var p = new Promise(function (resolve, reject) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                //readyState表示文档状态
                if (xhr.readyState != 4) return;
                if (xhr.readyState == 4 && xhr.status == 200){
                    //处理正常情况
                    resolve(xhr.responseText);
                }else {
                    reject('服务器错误');
                }
            };
            xhr.open('get',url);
            xhr.send(null);
        });
        return p;
    }
    //链式调用解决回调地狱,return一个新的调用就可以继续调用新的then()了。
    getText('http://localhost:8088/saymo').then(
        function (data) {
            alert(data);
            return  getText('http://localhost:8088/sayyi');
        },function (info) {
            alert(info);
        }
    ).then(
        function (data) {
            alert(data);
            return getText('http://localhost:8088/sayfeng')
        }
    ).then(
        function (data) {
            alert(data);
        }
    );
</script>

2.4 Promise常用API

2.4.1 实例方法

  1. p.then() #输出执行结果

  2. p.catch() #捕获异常

  3. p.finally() #无论正常还是异常都会执行

<script>
    function foo() {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                //resolve(123)//正常情况
                reject("出错了");//错误情况
            },1000)
        })
    }
    foo().then(function (data) {
        alert(data);
    }).catch(function (data) {
        alert(data);
    }).finally(function () {
        alert("结束了")
    })
    //与上面效果相同
    foo().then(function (data) {
        alert(data);
    },function (data) {
        alert(data);
    }).finally(function () {
        alert("结束了")
    })
</script>

2.4.2 对象方法

Promise.all() #并发处理多个异步任务,只有所有任务都执行完成才可以得到结果

Promise.race() #并发处理多个异步任务,只要有一个执行完成就可以得到结果

<script>
    function getText(url) {
        var p = new Promise(function (resolve, reject) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                //readyState表示文档状态
                if (xhr.readyState != 4) return;
                if (xhr.readyState == 4 && xhr.status == 200){
                    //处理正常情况
                    resolve(xhr.responseText);
                }else {
                    reject('服务器错误');
                }
            };
            xhr.open('get',url);
            xhr.send(null);
        });
        return p;
    }

    var p1 = getText("http://localhost:8088/saymo");
    var p2 = getText("http://localhost:8088/sayyi");
    var p3 = getText("http://localhost:8088/sayfeng");

    //result是一个数组形式的三个数据,顺序和p1,p2,p3顺序相同
    Promise.all([p1,p2,p3]).then(function (result) {
        alert(result);
    })
    //result返回一个数据,最快返回的一个
    Promise.race([p1,p2,p3]).then(function (result) {
        alert(result);
    })
</script>

2.5 Fetch接口调用

还有一种更加简便的方法,就是使用fetch接口进行调用,这个是基于Promise实现的

2.5.1 fetch的基本语法

  1. 语法结构
fetch(url).then(fn2)
          .then(fn3)
          ...
          .cach(fn)
  1. 基本用法
fetch('/abc').then(data=>{
    return data.text();
}).then(ret=>{
    //这里得到的才是最终的数据
    console.log(ret);
})

2.5.2 fetch请求参数

  1. 常用配置选项

method(String):HTTP请求方法,默认为GET(GET、POST、PUT、DELETE)

body(String):HTTP的请求参数

headers(Object):HTTP的请求头,默认为{}

  1. get请求参数传递
<script>
    fetch('http://localhost:8088/sayHi?name="莫逸风',{
        method:'get'
    }).then(function (data) {
        return data.text();
    }).then(function (data) {
        alert(data);
    });
</script>
  1. post请求参数传递

参数form表单形式

fetch('http://localhost:8088/login',{
        method:'post',
        body:,
        headers:{
            'Content-Type':'application/x-www-form-urlencoded',

        // Content-Type还有下面三种形式
        //1.  multipart/form-data
        //2.  application/json
        //3.  text/xml 
        }
    }).then(function (data) {
        return data.text();
    }).then(function (data) {
        alert(data);
    })

参数json表单形式

fetch('http://localhost:8088/login',{
        method:'post',
        body:JSON.stringify({
            name:'莫逸风',
            pass:'1234',
        }),
        headers:{
            'Content-Type':'application/json',
        }
    }).then(function (data) {
        return data.text();
    }).then(function (data) {
        alert(data);
    });
  1. 返回响应类型

text():将返回体处理成字符串类型

json():返回结果和JSON.parse(responseText)一样

2.6 Axios进行接口调用

axios(官网:https://github.com/axios/axios)是一个基于Promise用于浏览器和node.js的HTTP客户端

它具有以下特征:

  • 支持浏览器和node.js
  • 支持promise
  • 能拦截请求和相应
  • 自动转换JSON数据

2.6.1 axios基本用法

//去github下载文件,此js位于axios-master\dist
<script src="axios.js"></script>
<script>
    axios.get('http://localhost:8088/saymo').then(function (ret) {
        //data属性是固定的用法,用于获取后台的实际数据
        alert(ret.data)
    })
</script>

2.6.2 axios常用API

  • get:查询数据
  • post:添加数据
  • put:修改数据
  • delete:删除数据
  1. get传递参数

通过URL传递参数

axios.get('http://localhost:8088/sayhi?name=莫逸风').then(function (ret) {
        alert(ret.data)
    })

通过params传递参数

axios.get('http://localhost:8088/sayhi',{
        params:{
            name:"莫逸风"
        }
    }).then(function (ret) {
        //data属性是固定的用法,用于获取后台的实际数据
        alert(ret.data)
    })
  1. post传递参数

通过对象传递参数,默认为json格式

axios.post('http://localhost:8088/login',{
        name:"莫逸风",
        pass:"1234",
    }).then(function (ret) {
        //data属性是固定的用法,用于获取后台的实际数据
        alert(ret.data)
    })

通过URLSearchParams传递参数

var param = new URLSearchParams();
param.append('name','莫逸风');
param.append('pass','12345');
    axios.post('http://localhost:8088/login',param).then(function (ret) {
        //data属性是固定的用法,用于获取后台的实际数据
        alert(ret.data)
    })
  1. axios的响应结果
  • data:实际响应回来的数据
  • headers:响应头信息
  • status:响应状态码
  • statusText:响应状态信息
axios.post('http://localhost:8088/login',param).then(function(ret){
    console.log(ret);//所有数据都包含在此对象中
    //对于json形式的响应数据可以直接获取,不需要转换
    alert(ret.data.name);
})
  1. axios的全局配置
axios.defaults.timeout = 3000;  //超时时间
//默认地址,再写请求的时候只需要写后面的路由就行了
axios.defaults.baseURL = 'http://localhost:3000/app';
axios.defaults.headers['mytoken']='aqwerwqwerqwer2ewrwe23eresdff23'//设置请求头
  1. axios拦截器

请求拦截器

//在这里就是在请求之前设置了拦截器,用于获取网页http://localhost:8088/
axios.interceptors.request.use(function (config) {
        config.baseURL = "http://localhost:8088/";
        alert(config.url);
        return config;
    },function (err) {
        console.log(err);
    })

    axios.get('sayhi?name=莫逸风').then(function (ret) {
        //data属性是固定的用法,用于获取后台的实际数据
        alert(ret.data)
    })

响应拦截器

axios.interceptors.response.use(function (res) {
        var data = res.data;
        return data;
    },function (err) {
        console.log(err);
    })

    axios.get('sayhi?name=莫逸风').then(function (res) {
        //data属性是固定的用法,用于获取后台的实际数据
        alert(res)
    })

2.7 asyns/await接口调用

2.7.1 async/await的基本用法

  • async/await是ES7引入的语法,可以更加方便的进行异步操作
  • async关键字用于函数上(async函数的返回值是Promise实例对象)
  • await关键字用于async函数中(await可以得到异步的结果)
<script src="axios.js"></script>
<script>
    axios.defaults.baseURL = 'http://localhost:8088/';
    async function queryData(){
        var ret = await axios.get('saymo');
        //alert(ret.data);
        return ret.data;
    }
    queryData().then(function (data) {
        alert(data);
    });
</script>

异步请求

<script>
    axios.defaults.baseURL = 'http://localhost:8088/';
    async function queryData(){
        var ret = await axios.get('saymo');
        alert(ret.data);
        var ret1 = await axios.get('sayyi');
        alert(ret1.data);
        var ret2 = await axios.get('sayfeng');
        return ret2.data;
    }
    queryData().then(function (data) {
        alert(data);
    });
</script>

本文转载自: https://blog.csdn.net/young_man2/article/details/129667039
版权归原作者 young_man2 所有, 如有侵权,请联系我们删除。

“VUE进行前后端交互”的评论:

还没有评论