跨域指的是不同的站点之间,用ajax没办法相互进行调用的问题。它的本质是浏览器的一种保护机制。它其实就是为了保证用户的安全,防止出现恶意网站盗取数据。但是,这个保护机制也带了新问题:不同站点之间的正常调用有阻碍障碍。
(1)请求协议不同
(2)域名不同
(3)端口不同
我们在使用过程中,出现了上面的任意一种情况都属于跨域问题。包括如果说域名一样,但是请求协议不一样也是跨域问题。
常见的跨域如下所示:
当前url | 被请求的url | 是否跨域 |
http://www.nflang.com/ | http://www.nflang.com/login.html | 否 |
http://www.nflang.com/ | https://www.nflang.com/login.html | 是 |
http://www.nflang.com/ | http://www.nflang1.com/ | 是 |
http://www.nflang.com/ | http://blog.nflang.com/ | 是 |
http://www.nflang.com:8080/ | http://www.nflang.com:8091/ | 是 |
我们一般会有一个前端项目、一个后端项目,两个服务端口不一样,前端项目端口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 test(HttpServletResponse response) {
// 设置跨域
response.setHeader("Access-Control-Allow-Origin", "*");
return new HashMap() {{
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;
}
}