经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
SpringBoot怎么处理跨域请求
来源:cnblogs  作者:风尘博客  时间:2019/8/26 8:53:32  对本文有异议

一、跨域背景

1.1 何为跨域?

Url的一般格式:

协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址

示例:

https://www.dustyblog.cn:8080/say/Hello 是由

https + www + dustyblog.cn + 8080 + say/Hello
组成。

只要协议,子域名,主域名,端口号这四项组成部分中有一项不同,就可以认为是不同的域,不同的域之间互相访问资源,就被称之为跨域。

1.2 一次正常的请求

  • Controller层代码:
  1. @RequestMapping("/demo")
  2. @RestController
  3. public class CorsTestController {
  4. @GetMapping("/sayHello")
  5. public String sayHello() {
  6. return "hello world !";
  7. }
  8. }
  • 启动项目,测试请求

浏览器打开localhost:8080/demo/sayHello

可以打印出“hello world”

1.3 跨域测试

以Chrome为例:

  • 打开任意网站,如:https://blog.csdn.net

  • 按F12,打开【开发者工具】,在里面的【Console】可以直接输入js代码测试;

  1. var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
  2. var xhr = new XMLHttpRequest();
  3. xhr.open('GET', 'http://127.0.0.1:8080/demo/sayHello');
  4. xhr.setRequestHeader("x-access-token",token);
  5. xhr.send(null);
  6. xhr.onload = function(e) {
  7. var xhr = e.target;
  8. console.log(xhr.responseText);
  9. }
  • 输入完后直接按回车键就可以返回结果:
  1. Access to XMLHttpRequest at 'http://127.0.0.1:8080/demo/sayHello'
  2. from origin 'https://blog.csdn.net' has been blocked by CORS policy:
  3. No 'Access-Control-Allow-Origin' header is present on the requested resource.

该结果表明:该请求在https://blog.csdn.net域名下请求失败!

二、解决方案 - Cors跨域

2.1 Cors是什么

CORS全称为Cross Origin Resource Sharing(跨域资源共享), 每一个页面需要返回一个名为Access-Control-Allow-Origin的http头来允许外域的站点访问,你可以仅仅暴露有限的资源和有限的外域站点访问。

我们可以理解为:如果一个请求需要允许跨域访问,则需要在http头中设置Access-Control-Allow-Origin来决定需要允许哪些站点来访问。如假设需要允许https://www.dustyblog.c这个站点的请求跨域,则可以设置:

Access-Control-Allow-Origin:https://www.dustyblog.cn。

2.2 方案一:使用@CrossOrigin注解

2.2.1 在Controller上使用@CrossOrigin注解

该类下的所有接口都可以通过跨域访问

  1. @RequestMapping("/demo2")
  2. @RestController
  3. //@CrossOrigin //所有域名均可访问该类下所有接口
  4. @CrossOrigin("https://blog.csdn.net") // 只有指定域名可以访问该类下所有接口
  5. public class CorsTest2Controller {
  6. @GetMapping("/sayHello")
  7. public String sayHello() {
  8. return "hello world --- 2";
  9. }
  10. }

这里指定当前的CorsTest2Controller中所有的方法可以处理https://csdn.net域上的请求,这里可以测试一下:

  • https://blog.csdn.net页面打开调试窗口,输入(注意:这里请求地址是/demo2,请区别于1.2 案例中的/demo)
  1. var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
  2. var xhr = new XMLHttpRequest();
  3. xhr.open('GET', 'http://127.0.0.1:8080/demo2/sayHello');
  4. xhr.setRequestHeader("x-access-token",token);
  5. xhr.send(null);
  6. xhr.onload = function(e) {
  7. var xhr = e.target;
  8. console.log(xhr.responseText);
  9. }

返回结果:

  1. ? (e) {
  2. var xhr = e.target;
  3. console.log(xhr.responseText);
  4. }
  5. VM156:8 hello world --- 2

说明跨域成功!

  • 换个域名测试一下看跨域是否还有效,在https://www.baidu.com按照上述方法测试一下,返回结果:
  1. OPTIONS http://127.0.0.1:8080/demo2/sayHello 403
  2. (anonymous)
  3. Access to XMLHttpRequest at 'http://127.0.0.1:8080/demo2/sayHello'
  4. from origin 'http://www.cnblogs.com' has been blocked by CORS policy:
  5. Response to preflight request doesn't pass access control check:
  6. No 'Access-Control-Allow-Origin' header is present on the requested resource.

说明跨域失败!证明该方案成功指定了部分域名能跨域!

2.3 方案二:CORS全局配置-实现WebMvcConfigurer

  • 新建跨域配置类:CorsConfig.java:
  1. /**
  2. * 跨域配置
  3. */
  4. @Configuration
  5. public class CorsConfig implements WebMvcConfigurer {
  6. @Bean
  7. public WebMvcConfigurer corsConfigurer()
  8. {
  9. return new WebMvcConfigurer() {
  10. @Override
  11. public void addCorsMappings(CorsRegistry registry) {
  12. registry.addMapping("/**").
  13. allowedOrigins("https://www.dustyblog.cn"). //允许跨域的域名,可以用*表示允许任何域名使用
  14. allowedMethods("*"). //允许任何方法(post、get等)
  15. allowedHeaders("*"). //允许任何请求头
  16. allowCredentials(true). //带上cookie信息
  17. exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
  18. }
  19. };
  20. }
  21. }
  • 测试,在允许访问的域名https://www.dustyblog.cn/控制台输入(注意,这里请求的是http://127.0.0.1:8080/demo3):
  1. var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
  2. var xhr = new XMLHttpRequest();
  3. xhr.open('GET', 'http://127.0.0.1:8080/demo3/sayHello');
  4. xhr.setRequestHeader("x-access-token",token);
  5. xhr.send(null);
  6. xhr.onload = function(e) {
  7. var xhr = e.target;
  8. console.log(xhr.responseText);
  9. }

输出结果

  1. ? (e) {
  2. var xhr = e.target;
  3. console.log(xhr.responseText);
  4. }
  5. VM433:8 hello world --- 3

说明跨域成功,换个网址如https://www.baidu.com测试依旧出现需要跨域的错误提示,证明该配置正确,该方案测试通过。

2.3 拦截器实现

通过实现Fiter接口在请求中添加一些Header来解决跨域的问题

  1. @Component
  2. public class CorsFilter implements Filter {
  3. @Override
  4. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  5. throws IOException, ServletException {
  6. HttpServletResponse res = (HttpServletResponse) response;
  7. res.addHeader("Access-Control-Allow-Credentials", "true");
  8. res.addHeader("Access-Control-Allow-Origin", "*");
  9. res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
  10. res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
  11. if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
  12. response.getWriter().println("ok");
  13. return;
  14. }
  15. chain.doFilter(request, response);
  16. }
  17. @Override
  18. public void destroy() {
  19. }
  20. @Override
  21. public void init(FilterConfig filterConfig) throws ServletException {
  22. }
  23. }

三、更多

3.1 源码地址

Github 示例代码

原文链接:http://www.cnblogs.com/vandusty/p/11408422.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号