一、什么是前后端分离架构
1、传统web系统开发网站架构
分成三层架构:
com.xxx.dao:数据库访问层
com.xxx.service:业务逻辑层
com.xxx.controller:控制层(需要控制页面跳转)
2、微服务架构
前后端分离,专业的人做专业的事情。
前端:前端工程师 vue ajax
后端:后端工程师 go java php
前端工程师承接了controller层页面的部分。
二、什么是网站跨域问题
1、网站访问
2、跨域问题,发生在浏览器中安全策略
跨域问题是浏览器的一种安全策略,访问需要遵循同源策略。
发生了跨域的问题:
可以请求到后端,但是无法获取到响应结果。
前端vue地址为:vue.xxx.com
后端接口地址为:api.xxx.com
前端访问后端就不同源了。发送ajax请求的域名,和浏览器的域名不一样,浏览器会有一个保护机制。浏览器发送请求给后端,后端响应结果,浏览器会拦截。
3、同源策略
(1)浏览器访问的地址【协议://ip:端口】
(2)在该页面中访问ajax请求【协议://ip:端口】必须要与我们浏览器所访问的【协议://ip:端口】一致。
(3)如果不一致的话,则会发生跨域问题,浏览器触发保护机制,获取不到该请求的响应结果。
三、什么情况下不会发生跨域问题
1、nginx转发
nginx发现html开头,转发到前端服务器。
nginx发现api开头,转发到后端服务器。
四、跨域有哪些解决方案
解决跨域的问题:
1、使用解决跨域的注解@CrossOrigin,底层就是在响应头中设置允许跨域的参数
2、过滤拦截器aop,nginx、网关在响应头中设置允许跨域的参数
3、使用nginx保证html与ajax接口,同协议、同ip(域名)、同端口
4、Jsonp解决跨域的问题,不能使用post请求,只支持get请求,很少使用
五、@CrossOrigin解决跨域的原理
1、@CrossOrigin底层在响应头中,加上了一个参数
Access-Control-Allow-Origin: *
2、解决跨域问题原理
就是在接口响应头,允许前端跨域访问该接口。
HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
response.setHeader("Access-Control-Allow-Origin", "*");
六、自己封装一个@MyCrossOrigin注解
1、注解底层原理实现
aop+反射机制
2、pom文件添加依赖
<!--AOP支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
3、添加注解类MyCrossOrigin.java
package com.example.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyCrossOrigin {
}
4、添加注解处理类MyCrossOriginAop.java
package com.example.annotation;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class MyCrossOriginAop {
@Before(value = "@annotation(com.example.annotation.MyCrossOrigin)")
public void before() {
//如果接口上有加上该注解MyCrossOrigin,自动走前置通知的代码
System.out.println("----------前置通知----------");
HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
response.setHeader("Access-Control-Allow-Origin", "*");
}
}
5、在方法上使用@MyCrossOrigin注解
package com.example.web;
import java.util.HashMap;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.example.annotation.MyCrossOrigin;
@RestController
public class CORSController {
@RequestMapping("/hello2")
@MyCrossOrigin
public HashMap<String, String> hello2() {
HashMap<String, String> result = new HashMap<>();
result.put("code", "200");
result.put("msg", "ok");
// HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
// response.setHeader("Access-Control-Allow-Origin", "*");
return result;
}
}
七、项目比较小的前后端分离方案
1、注解@CrossOrigin
2、过滤器—自己拦截每个请求
3、在每个接口中加上Access-Control-Allow-Origin
代码冗余,不推荐
八、项目比较大的前后端分离方案
1、基于nginx
2、基于网关
3、nginx反向代理