1.什么是跨域问题呢?
跨域指的是不同的站点之间,用ajax没办法相互进行调用的问题。它的本质是浏览器的一种保护机制。它其实就是为了保证用户的安全,防止出现恶意网站盗取数据。但是,这个保护机制也带了新问题:不同站点之间的正常调用有阻碍障碍。
2.跨域的几种情况
(1)请求协议不同
(2)域名不同
(3)端口不同
我们在使用过程中,出现了上面的任意一种情况都属于跨域问题。包括如果说域名一样,但是请求协议不一样也是跨域问题。
常见的跨域如下所示:
我们一般会有一个前端项目、一个后端项目,两个服务端口不一样,前端项目端口8081,后端项目8080。前端项目在调用后端接口时候会出现跨域问题。
下面呢给大家提供几种解决办法:
(1)使用 @CrossOrigin 注解实现跨域;
使用 @CrossOrigin 注解可以轻松的实现跨域,此注解既可以修饰类,也可以修饰方法。当修饰类时,表示此类中的所有接口都可以跨域;当修饰方法时,表示此方法可以跨域。代码实现如下:
package com.test.controller; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.nimbusds.jose.JWSObject; @RestController @CrossOrigin(origins = "*") @RequestMapping("/login") public class LoginController { @Autowired private SysUserService sysUserService; /** * 登录 */ @PostMapping("/userLogin") @ApiOperation(value = "校验登录账号", response = ApiResult.class) public ApiResult userLogin(@RequestBody SysUserQueryVo sysUserQueryVo){ try { ApiResult apiResult = sysUserService.userLogin(sysUserQueryVo); System.out.println("测试登录"); return apiResult; } catch (Exception e) { log.info("用户登录失败"+e.getMessage()); throw new DaoException("用户登录失败"+e.getMessage()); } } }
(2)通过配置文件实现跨域;
- 创建一个新配置文件;
- 添加 @Configuration 注解,实现 WebMvcConfigurer 接口;
- 重写 addCorsMappings 方法,设置允许跨域的代码。、
代码实现如下所示:
package com.test.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class MyCorsFilter { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); //开放哪些ip、端口、域名的访问权限,星号表示开放所有域 config.addAllowedOrigin("*"); //是否允许发送Cookie信息 config.setAllowCredentials(true); //开放哪些Http方法,允许跨域访问 config.addAllowedMethod("*"); //允许HTTP请求中的携带哪些Header信息 config.addAllowedHeader("*"); //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息) // config.addExposedHeader("*"); config.addExposedHeader("Content-Type"); config.addExposedHeader( "X-Requested-With"); config.addExposedHeader("accept"); config.addExposedHeader("Origin"); config.addExposedHeader( "Access-Control-Request-Method"); config.addExposedHeader("Access-Control-Request-Headers"); //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置 UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); configSource.registerCorsConfiguration("/**", config); return new CorsFilter(configSource);} }
(3)通过 CorsFilter 对象实现跨域;
该实现方式和(2)里面的实现方式类似,他也能够实现全局跨域。
代码实现如下所示:
package com.test.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class MyCorsFilter { @Bean public CorsFilter corsFilter() { // 1.创建 CORS 配置对象 CorsConfiguration config = new CorsConfiguration(); // 支持域 config.addAllowedOriginPattern("*"); // 是否发送 Cookie config.setAllowCredentials(true); // 支持请求方式 config.addAllowedMethod("*"); // 允许的原始请求头部信息 config.addAllowedHeader("*"); // 暴露的头部信息 config.addExposedHeader("*"); // 2.添加地址映射 UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource(); corsConfigurationSource.registerCorsConfiguration("/**", config); // 3.返回 CorsFilter 对象 return new CorsFilter(corsConfigurationSource); } }
(4)通过 Response 对象实现跨域;
该方式属于最原始的一种方式,但是它能够支持任意的版本的 Spring Boot(早期的 Spring Boot 版本也是支持的)。但此方式也是局部跨域,它应用的范围最小,设置的是方法级别的跨域。
代码实现如下:
com.test.login import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; @RestController public class LoginController { @RequestMapping("/test") public HashMap<String, Object> test(HttpServletResponse response) { // 设置跨域 response.setHeader("Access-Control-Allow-Origin", "*"); return new HashMap<String, Object>() {{ put("state", 200); put("data", "success"); put("msg", ""); }}; } }
(5)通过实现 ResponseBodyAdvice 实现跨域。
通过重写 ResponseBodyAdvice 接口中的 beforeBodyWrite(返回之前重写)方法,我们可以对所有的接口进行跨域设置。它也是实现的全局跨域,对整个项目的接口全部有效。
它的具体实现代码如下:
com.test.config import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; @ControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice { /** * 内容是否需要重写 * 返回 true 表示重写 */ @Override public boolean supports(MethodParameter returnType, Class converterType) { return true; } /** * 方法返回之前调用此方法 */ @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { // 设置跨域 response.getHeaders().set("Access-Control-Allow-Origin", "*"); return body; } }