前后端分离中Cors跨域问题解决方法总结

序言

        目前项目开发流行前后端分离,前后分离势必会出现CORS问题了。CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。本文主要讨论前后端分离之后对于Cors问题的解决方案。需要说明的是本文章前端使用Angular9,后端使用的是SpringBoot 2.1.3.RELEASE。

一、场景

        前端发起请求主要关注JSON形式和JSONP形式。

1.1 JSON数据请求场景

        前端请求代码实现形式,这里使用的是HttpClientModule。

```

doPost() {
  const url = `http://localhost:8080/interface/testPost`;
  const httpOptions =  {
    headers: new HttpHeaders({'Content-Type': 'application/json'})
  };
  this.httpClient.post(url,{"username":"张三丰","age":45}, httpOptions).subscribe( (response) => {
    console.log(response);
    this.masterInfo = response;
  });
}

```

后端SpringBoot应用解决Json数据请求的跨域问题有多种:

1、使用@CrossOrigin注解来实现跨域,使用注解可以以最细粒度控制可跨域范围,此注解可添加在Controller类上和方法上,Spring Framework 4.2开始支持此注解。

2、CORS全局配置一个CorsConfigure类实现WebMvcConfigure接口或者继承WebMvcConfigurerAdapter类,形式都是一样,都是给CorsRegistry 设置跨域允许的请求源:

```

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                .maxAge(3600)
                .allowCredentials(true);
    }

```

3、实现Filter接口自定义一个允许跨域的过滤器

```

@WebFilter(urlPatterns = "/*")
public class CorsFilter implements Filter {
 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException,
            ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin","*");
        filterChain.doFilter(request, servletResponse);
    }
 
    @Override
    public void destroy() {
 
    }
 
    @Override
    public void init(FilterConfig arg0) throws ServletException {
 
    }
}

```

1.2 JSONP数据请求场景

        这需要说明一下浏览器的特性,浏览器不允许页面中的脚本程序跨域读取数据,但却允许HTML引用跨域的资源,如图片,CSS和脚本程序。对于脚本程序的引用比较特殊,它被浏览器解析以后,就和本地的脚本程序别无二致且可立即进行解释并执行。

前端JSONP请求需要用到的依赖HttpClientJsonpModule。请求实现方式是使用HttpClient发起jsonp请求。

```

  getJSONP() {
    /* jsonp请求,需要服务器支持才行 */
    const url = `http://localhost:8080/interface/testJSONP`;
    this.httpClient.jsonp(url, "CallBack").subscribe((response: any) => {
      console.log(response);
      console.log(response.master);
    });
  }

```

服务器端接口对应的实现方式,这里使用的JSONObject是阿里的fastjson

```

    @RequestMapping("/testJSONP")
    @ResponseBody
    public String testJSONP(@RequestParam("CallBack") String callback) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("result","200");
        jsonObject.put("master","charberming");
        jsonObject.put("appname","app1");
        return callback+"("+jsonObject+")";  
    }

```

        这里返回的数据必须是由前端请求url上带着的callback参数拼接的json字符串格式,否则前端会报错。在这里由于我们在前端请求参数中设置的回调参数为CallBack,所以在服务端程序中,我们要拿到的参数也是CallBack,保持一致。

        注:主要是在学习angular过程中,出现跨域问题,网上找的办法主要是在前端设置,比如说angular设置代理文件启动,还有说使用nginx反向代理,前者说是能解决跨域问题,但是后者就太扯淡了,但还是都去验证了下,没成功。因此在这里做一些总结,以节省道友时间。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章