跨域问题解决思路

本文涉及的产品
.cn 域名,1个 12个月
简介: 在项目中经常遇到跨域问题,那么怎样解决跨域问题呢,下面提供几种解决跨域问题的解决思路。

一、跨域是什么?

跨域(CORS)是指不同域名之间相互访问,顾名思义,指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略所造成的,是浏览器对于JavaScript所定义的安全限制策略。

1.1 同源策略

     跨域问题其实就是浏览器的同源策略所导致的。

同源策略是一个重要的安全策略,它用于限制一个origin(opens new window)的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

当跨域时会收到以下错误:

1.2 同源实例

例:https://www.xxx.com:80/path/to/myfile.html?key1=value1#Somewhere

只有当protocol(协议)、domain(域名)、port(端口)三者一致,才是同源。

1.3 简单请求和非简单请求

常见的简单请求:

1、请求方法为:HEAD、GET、POST中的一种;

2、HTTP请求头中字段不超过:Accept、Accept-Language、Content-Language、Last-Event-ID;

3、Content-Type字段值为application/x-www-form-urlencoded、multipart/form-data、text/plain中的一种。

非简单请求:

1、请求方法为put、delete;

2、发送JSON格式的ajax请求;

3、http中带自定义请求头。

对于简单请求:

浏览器发现是跨域请求,就会自动在请求头中加上Origin字段,代表请求来自哪个域(协议+主机名+端口号)。服务器在收到请求后,根据请求头中Origin字段值来判断是否允许跨域请求通过。具体实现方法是:在响应头Access-Control-Allow-Origin字段中设置指定的域名,表示允许这些域名的跨域请求。如果请求头中Origin字段的域名包含在这些域名中,则可以实现跨域请求(当然有时候还需要结合其他字段来判断),否则不通过。例如:

请求头信息

GET /cors http 1.1

Origin:http://localhost:8080/

connection:keep-active

响应头信息

Access-Control-Allow-Origin://localhost:8080/

Access-Control-Allow-Credentials:true

Content-Type:text/html;chatset=utf-8

非简单请求:

非简单请求在发送http请求时,会预先发送一次“预检”(OPTIONS)请求。预检请求会事先询问服务器,当前域名是否在服务器允许的范围内,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复后,浏览器才会真正发出http请求,否则就会报错。

解决跨域可以在客户端访问服务端时拦截以下请求头设置:

Access-Control-Allow-Origin

标识允许哪个域的请求

Access-Control-Allow-Methods

请求方法

Access-Control-Max-Age

本次预检请求的有效期,单位为秒

Access-Control-Allow-Headers

响应首部

Access-Control-Allow-Credentials

允许客户端携带验证信息

2. 如何解决跨域

2.1 JSONP

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。Jsonp实现的前提:浏览器允许跨越加载同源数据。即在JavaScript脚本中发送请求,就可以远程加载js格式数据。JSONP只支持GET请求。

请求原理:

(1)异步请求的时候,加上一个名为callback的回调函数(该函数前后端要保持一致);

(2)在接口中,将返回的json格式数据,伪装(包装)成js脚本格式;

(3)得到js格式数据后,提取里面的json数据。

Jquery在发送一个Ajax jsonp请求时,会在访问链接的后面自动加上一个验证参数,这个参数是Jquery随机生成的,例如链接:https://www.xxx.com/path/to/myfile?callback=jQuery311098773333_23224424444222,jsonp对接的后端接口:

@ResponseBody
@RequestMapping("/getMyJsonp")
public String getMyJsonpSuccess(@RequestParam("callback") String callback){
  Gson gson=new Gson();
  Map map = new HashMap<>();
  map.put("seat","测试jsonp接口");
  return callback+"("+gson.toJson(map)+")";
}

2.2 拦截请求头

2.2.1使用Filter方式进行设置

使用Filter过滤器来过滤服务请求,向请求端设置Response Header(响应头部)的Access-Control-Allow-Origin属性声明允许跨域访问。

@WebFilter
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(req, res);
    }
}

2.2.2继承 HandlerInterceptorAdapter(拦截器方式)

@Component
public class CrossInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        return true;
    }
}

2.2.3实现WebMvcConfigurer

@Configuration
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 拦截所有的请求
                .allowedOrigins("http://www.xxx.com")  // 可跨域的域名,可以为 *
                .allowCredentials(true)
                .allowedMethods("*")   // 允许跨域的方法,可以单独配置
                .allowedHeaders("*");  // 允许跨域的请求头,可以单独配置
    }
}

2.3 使用 @CrossOrgin 注解

@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/{id}")
    public User get(@PathVariable Long id) {
    }
    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
    }
}

@CrossOrgin源码如下:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
    /** @deprecated */
    @Deprecated
    String[] DEFAULT_ORIGINS = new String[]{"*"};
    /** @deprecated */
    @Deprecated
    String[] DEFAULT_ALLOWED_HEADERS = new String[]{"*"};
    /** @deprecated */
    @Deprecated
    boolean DEFAULT_ALLOW_CREDENTIALS = true;
    /** @deprecated */
    @Deprecated
    long DEFAULT_MAX_AGE = 1800L;
    @AliasFor("origins")
    String[] value() default {};
    @AliasFor("value")
    String[] origins() default {};
    String[] allowedHeaders() default {};
    String[] exposedHeaders() default {};
    RequestMethod[] methods() default {};
    String allowCredentials() default "";
    long maxAge() default -1L;
}

其本质也是通过拦截请求头进行处理。

2.4 使用Nginx配置

location / {
   add_header Access-Control-Allow-Origin *;
   add_header Access-Control-Allow-Headers X-Requested-With;
   add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
   if ($request_method = 'OPTIONS') {
     return 204;
   }
}
相关文章
|
4月前
|
前端开发 API
uniapp中为什么会出现跨域问题,如何解决
uniapp中为什么会出现跨域问题,如何解决
1840 0
|
4月前
|
JSON 前端开发 JavaScript
详细剖析让前端头疼的跨域问题是怎么产生的,又该如何解决
详细剖析让前端头疼的跨域问题是怎么产生的,又该如何解决
|
4月前
|
前端开发 JavaScript 应用服务中间件
前端程序员必须要知道的跨域问题以及解决方法
前端程序员必须要知道的跨域问题以及解决方法
|
缓存 安全 前端开发
【从原理到实战】彻底搞懂跨域问题 (一)(2)
3、预检请求的优化 复杂请求会发预检请求, 相当于每个接口会发两次请求, 比较消耗资源, 那么是可以对预检请求进行优化, 可以采用以下两种方式 设置预检请求的缓存时长
88 0
|
4月前
|
JSON 前端开发 JavaScript
前端跨域问题
前端跨域问题
65 0
|
JavaScript 前端开发 中间件
前端解决跨域问题(9个方法)
前端解决跨域问题(9个方法)
1507 0
|
XML JSON 安全
【从原理到实战】彻底搞懂跨域问题 (一)(1)
前言 什么是跨域: 浏览器为了安全性,设置同源策略导致的, 或者说是一种浏览器的限制 同源策略: 是一种约定,WEB 应用只能请求同一个源的资源 什么时候会跨域: 协议名、域名、端口号 不同 本文将从原理, 到最简代码实现, 演示解决跨域的方法和流程,纸上得来终觉浅 绝知此事要躬行, 只有自己手敲实现过, 才能对其原理理解更加深刻。
398 0
|
JSON 前端开发 JavaScript
跨域问题的解决方案 jsonp cros原理
当浏览器端运行了一段ajax代码(无论是使用XMLHttpRequest还是fetch api),浏览器会首先判断它属于哪一种请求模式
跨域问题的解决方案 jsonp cros原理
|
前端开发 JavaScript
前端静态页面基本开发思路(二)
由于第一篇的反响不错,所以今天抽空写写前端静态页面基本开发思路(二) 第一篇开发思路直通车→前端静态页面基本开发思路(一) 现在的静态页面的设计基本上都涉及到了轮播图,而且一般都是顶部菜单栏过了就是轮播图的区域,比如小米官网,京东官网等,所以今天我们就从轮播图的实现开始讲
126 2
前端静态页面基本开发思路(二)
|
编解码 前端开发 JavaScript
前端静态页面基本开发思路(一)
有不少刚入门前端的同学经常问我前端布局的问题,总是跟我说在面对学校布置的作业或者想自己搭建博客的时候不知道怎么下手,不知道怎么去写静态的页面,每当我解决了一个又一个同学的问题的时候,又有新的同学来问,故思来想去,还是出一篇博客来讲一下怎么去开发前端静态页面,开发的基本思路是什么
216 2
前端静态页面基本开发思路(一)