目录

一、 跨域

1. 什么是跨域?

2. 什么是本域?

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

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

1. SpringBoot上直接添加@CrossOrigin

2. 处理跨域请求的Configuration

3. 采用过滤器的方式

3.1 方式一

 3.2 方式二

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

三、VUE的前后端交互

1. 前后端交互模式

1.1 传统的交互方式

1.2 传统的URL

1.3RESTFUL风格的URL

2. Promise相关概念与使用

2.1 promise使用的优势

2.2 promise的基本用法

2.3 then参数的函数返回值

2.4 Promise常用API

2.5 Fetch接口调用

2.5.1 fetch的基本语法

2.5.2 fetch请求参数

2.6 Axios进行接口调用

2.6.1 axios基本用法

2.6.2 axios常用API

2.7 asyns/await接口调用

2.7.1 async/await的基本用法


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

一、 跨域

1. 什么是跨域?

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

2. 什么是本域?

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

VUE进行前后端交互

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请求和响应的访问,并公开额外的服务器端处理相关属性和特性,如请求属性。

2. 

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是一个对象,从它可以获取异步操作的消息。

2.2 promise的基本用法

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)

2. 基本用法

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的请求头,默认为{}

2. get请求参数传递

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

3. 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);
    });

4. 返回响应类型

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

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

2.6 Axios进行接口调用

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

它具有以下特征:

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

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)
    })

2. 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)
    })

3. axios的响应结果

axios.post('http://localhost:8088/login',param).then(function(ret){
	console.log(ret);//所有数据都包含在此对象中
	//对于json形式的响应数据可以直接获取,不需要转换
	alert(ret.data.name);
})

4. axios的全局配置

axios.defaults.timeout = 3000;  //超时时间
//默认地址,再写请求的时候只需要写后面的路由就行了
axios.defaults.baseURL = 'http://localhost:3000/app';
axios.defaults.headers['mytoken']='aqwerwqwerqwer2ewrwe23eresdff23'//设置请求头

5. 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>

发表回复