前后端分离解决跨域问题

什么是跨域

跨域是指从一个域名的网页去请求另一个域名的资源,域名、端口、协议任一不同,都算作跨域。

基于安全考虑,浏览器对于javascript的同源策略的限制。

前端跨域

我们前端项目中采用MVVM框架vue.js,2.0以后尤大推荐用axios与后台交互。

功能特性

  • 在浏览器中发送 XMLHttpRequests 请求
  • 在 node.js 中发送 http请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 自动转换 JSON 数据
  • 客户端支持保护安全免受 XSRF 攻击

vue cli脚手架搭建只需要在config目录下的index.js增加changeOrigin的配置即可

dev: {
    env: require('./dev.env'),
    port: 8080,
    autoOpenBrowser: true,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      '/api': {
        target: 'http://localhost:8004',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }

还需要注意的是,axios 默认是没有携带 cookie 的,如果后台项目是用 session 认证用户信息的话,每次请求的 sessionId 是不一样的。

需要在axios配置中将 withCredentials 设置为 true。

正式环境中,vue.js 代码会被 build 成 html 文件在 nginx 中部署,转发请求到后端服务。

  location /api/ {
        proxy_pass http://web-server/;
        proxy_connect_timeout 600;
        proxy_read_timeout 600;
    }

后端跨域

后端主要是通过跨域资源共享(CORS) 来实现允许跨域请求,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。

在 spring boot 中有两种跨域方式,在没有启用 spring security 时,直接在请求的controller层注解,类或者方法上都可以,其中 @CrossOrigin 中的2个参数:

  • origins : 允许可访问的域列表
  • maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。
@CrossOrigin(origins = "http://www.baidu.com", maxAge = 3600)
@Api(tags = "数据源", description = "数据源业务类接口服务")
@RestController
@RequestMapping("/dataSource")
public class DataSourceAction {

    @Resource
    private DataSourceService service;

    @CrossOrigin()
    @ApiOperation("测试并保存数据源")
    @RequestMapping(value = "/saveDataSource", method = RequestMethod.POST)
    public void saveDataSource(@RequestParam Map map) throws Exception {
        service.testAndSave(map);
    }
}

也可以设置成全局

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author pilsy
 */
@Configuration
public class MiddlewareConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CorsMiddleware())
                .addPathPatterns("/**");
    }

    public class CorsMiddleware extends HandlerInterceptorAdapter {
        @Override
        public boolean preHandle(
                HttpServletRequest request,
                HttpServletResponse response,
                Object handler
        ) throws Exception {
            if (request.getMethod().equals("OPTIONS")) {
                response.addHeader("Access-Control-Allow-Origin", "*");
                response.addHeader("Access-Control-Allow-Credentials", "true");
                response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, DELETE");
                response.addHeader("Access-Control-Allow-Headers", "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,Authorization,If-Modified-Since,Cache-Control,Content-Type");
                response.addHeader("Access-Control-Max-Age", "3600");
                response.addHeader("charset", "utf-8");
            }
            return super.preHandle(request, response, handler);
        }
    }
}

在启用 spring security 后,由 security 管理跨域设置,首先实例化 CorsConfigurationSource

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(AllowedOrigins.getAllowedOrigin());
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE"));
        configuration.setAllowedHeaders(Arrays.asList("DNT", "X-Mx-ReqToken", "Keep-Alive", "User-Agent", "X-Requested-With", "Authorization", "If-Modified-Since", "Cache-Control", "Content-Type"));
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

再将 CorsConfigurationSource 注册到 security 配置项中

httpSecurity.cors().configurationSource(corsConfigurationSource());

你可能感兴趣的:(前后端分离解决跨域问题)