欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于SpringBoot解决CORS跨域的问题(@CrossOrigin)

程序员文章站 2022-11-17 12:55:10
一、关于跨域介绍在前后分离的架构下,跨域问题难免会遇见比如,站点 http://domain-a.com 的某 html 页面通过 的 src 请求 http://domain-b.com/image...

一、关于跨域介绍

在前后分离的架构下,跨域问题难免会遇见比如,站点 http://domain-a.com 的某 html 页面通过 的 src 请求 http://domain-b.com/image.jpg。

网络上的许多页面都会加载来自不同域的css样式表,图像和脚本等资源。

出于安全原因,浏览器限制从脚本内发起的跨源http请求。

例如,xmlhttprequest和fetch api遵循同源策略。

这意味着使用这些api的web应用程序只能从加载应用程序的同一个域请求http资源,除非使用cors头文件。

跨域的体现,在于它的域名不同或者端口不同,但要注意以下的形式为非跨域模式

http://www.example.com/index.html ==> http://www.example.com/login.html

二、spring boot跨域(@crossorigin)

当然这里虽然指springboot但是springmvc也是一样的,要求在spring4.2及以上的版本

1、@crossorigin使用场景要求

jdk1.8+

spring4.2+

2、@crossorigin源码解析(翻译参考网络,文末列出参考地址)

@target({ elementtype.method, elementtype.type })
@retention(retentionpolicy.runtime)
@documented
public @interface crossorigin {
  string[] default_origins = { "*" };
  string[] default_allowed_headers = { "*" };
  boolean default_allow_credentials = true;
  long default_max_age = 1800;
  /**
   * 同origins属性一样
   */
  @aliasfor("origins")
  string[] value() default {};
  /**
   * 所有支持域的集合,例如"http://domain1.com"。
   * <p>这些值都显示在请求头中的access-control-allow-origin
   * "*"代表所有域的请求都支持
   * <p>如果没有定义,所有请求的域都支持
   * @see #value
   */
  @aliasfor("value")
  string[] origins() default {};
  /**
   * 允许请求头重的header,默认都支持
   */
  string[] allowedheaders() default {};
  /**
   * 响应头中允许访问的header,默认为空
   */
  string[] exposedheaders() default {};
  /**
   * 请求支持的方法,例如"{requestmethod.get, requestmethod.post}"}。
   * 默认支持requestmapping中设置的方法
   */
  requestmethod[] methods() default {};
  /**
   * 是否允许cookie随请求发送,使用时必须指定具体的域
   */
  string allowcredentials() default "";
  /**
   * 预请求的结果的有效期,默认30分钟
   */
  long maxage() default -1;
}

3、@crossorigin使用

spring boot下的请求处理控制器

package com.example.demo.controller;
import com.example.demo.domain.user;
import com.example.demo.service.iuserfind;
import org.springframework.web.bind.annotation.crossorigin;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestparam;
import org.springframework.web.bind.annotation.restcontroller;
import javax.annotation.resource;
/**
 * @title: usercontroller
 * @projectname demo
 * @description: 请求处理控制器
 * @author 浅然
 * @date 2018/7/2022:18
**/
@restcontroller
//实现跨域注解
//origin="*"代表所有域名都可访问
//maxage飞行前响应的缓存持续时间的最大年龄,简单来说就是cookie的有效期 单位为秒
//若maxage是负数,则代表为临时cookie,不会被持久化,cookie信息保存在浏览器内存中,浏览器关闭cookie就消失
@crossorigin(origins = "*",maxage = 3600)
public class usercontroller {
  @resource
  private iuserfind userfind;
  @getmapping("finduser")
  public user finduser(@requestparam(value="id") integer id){
    //此处省略相应代码
  }
}

后台返回的数据

基于SpringBoot解决CORS跨域的问题(@CrossOrigin)

前端跨域请求

<!doctype html>
<html>
 <head>
 <meta charset="utf-8" />
 <title>demo</title>
 <script type="text/javascript" src="js/jquery-3.3.1.min.js" ></script>
 </head>
 <body>
 <input type="button" value="测试" onclick="ajaxloding()" />
 <div id="usermessage"></div>
 <script>
  var getdata=0;
  function ajaxloding(){
  $.ajax({
   async:false,
   type:"get",
   url:"http://localhost:8080/api/finduser?id=1",
   contenttype: "application/x-www-form-urlencoded",
   datatype: "json",
   data: {},
   success:function(result){
   getdata=result.name
   },
   error: function (errormsg) {
        //请求失败时执行该函数
        alert("请求数据失败!");
      }
  });
  $("#usermessage").text(getdata)
  }
 </script>
 </body>
</html>

这样就解决了跨域问题,获取了后台的数据

基于SpringBoot解决CORS跨域的问题(@CrossOrigin)

参考

跨域 http 请求

补充:springboot的@crossorigin("*")跨域仍然失效

项目中偶尔遇到即使加了@crossorigin跨域失败:

第一次遇到时间有限没解决:前端直接添加跨域处理。

jquery.support.cors = true;

后续第二次遇到该问题,作为后端不能让前端解决跨域问题。

debug详细查找原因:发现在自定义拦截器返回失败,跨域失败。

明白该问题:需要以下知识。

(mvc拦截器的链路模式)

(cors拦截器加载)

(自定义的拦截器加载)

(拦截器的加载顺序)

因为拦截器是链路模式:crossorigin也是拦截器在自定义拦截器之后。所以在自定义拦截器失败后,处理

跨域的拦截器未处理,造成跨域失败。

解决该问题的办法:

添加filter ,因为filter优先于拦截器执行,所以自己创建的拦截器不会影响跨域处理。

@configuration
public class corsconfig { 
  @bean
  public corsfilter corsfilter() {
    corsconfiguration config = new corsconfiguration();
    config.addallowedorigin("*");
    config.setallowcredentials(true);
    config.addallowedmethod("*");
    config.addallowedheader("*");
    urlbasedcorsconfigurationsource configsource = new urlbasedcorsconfigurationsource();
    configsource.registercorsconfiguration("/**", config);
    return new corsfilter(configsource);
  }
}

二:springboot升级到2.2.0,在新版本的springmvc中,把cors拦截添加到了拦截器的第一位,所以不会有该问题。

如果允许可以直接升级springboot或mvc版本。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。如有错误或未考虑完全的地方,望不吝赐教。