当前位置:首页 > 技术文章 > 正文内容

java 面试题:如何实现跨域?(怎么解决跨域问题java)

在 Java 中实现跨域(Cross-Origin Resource Sharing,CORS)主要有以下几种方式,具体选择取决于应用场景和架构设计:

一、前端代理(开发环境)

在开发环境中,可通过前端脚手架(如 Vue CLI、Create React App)配置代理服务器,将请求转发到后端 API。
优点:无需修改后端代码,仅开发环境使用。
缺点:生产环境需另寻方案。

示例(Vue CLI)

// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://backend-api.com', // 后端API地址
        changeOrigin: true,
        pathRewrite: { '^/api': '' }
      }
    }
  }
}

二、后端配置(生产环境主流方案)

1. Spring Boot(推荐)

通过添加@CrossOrigin注解或全局配置实现。

方法一:Controller 级别(局部)

@RestController
@RequestMapping("/api")
public class UserController {
    // 允许指定域名跨域
    @CrossOrigin(origins = "http://example.com")
    @GetMapping("/users")
    public List<User> getUsers() {
        return userService.getAllUsers();
    }
}

方法二:全局配置(推荐)

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 所有接口
                .allowedOrigins("*") // 允许所有域名
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的方法
                .allowedHeaders("*") // 允许的请求头
                .allowCredentials(true) // 允许携带Cookie
                .maxAge(3600); // 预检请求缓存时间
    }
}

2. Filter 配置(非 Spring 项目)

自定义 Filter 拦截所有请求并添加 CORS 响应头。

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", "GET, POST, PUT, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(req, res);
    }
}

在web.xml中注册 Filter:

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.example.CorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

三、Nginx 反向代理(生产环境)

通过 Nginx 将前端和后端请求代理到同一域名下,避免跨域问题。
配置示例

server {
    listen 80;
    server_name example.com;

    # 前端静态资源
    location / {
        root /path/to/frontend;
        index index.html;
    }

    # 后端API代理
    location /api/ {
        proxy_pass http://backend-api-server:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

四、JSONP(兼容性方案)

利用<script>标签不受同源策略限制的特性,仅支持 GET 请求。
后端实现

@GetMapping("/data")
public void getData(HttpServletRequest req, HttpServletResponse res) throws IOException {
    String callback = req.getParameter("callback"); // JSONP回调函数名
    String data = "{\"name\":\"John\",\"age\":30}"; // 返回数据
    
    res.setContentType("application/javascript");
    res.getWriter().write(callback + "(" + data + ")"); // 包装为函数调用
}

前端调用

<script>
function handleData(data) {
    console.log(data);
}
</script>
<script src="http://api.example.com/data?callback=handleData"></script>

五、CORS Filter 配置(细粒度控制)

对于复杂场景,可通过配置更细粒度的 CORS 策略。

@Bean
public CorsFilter corsFilter() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(Arrays.asList("http://example.com")); // 允许的域名
    config.setAllowedMethods(Arrays.asList("GET", "POST")); // 允许的方法
    config.setAllowCredentials(true); // 允许携带Cookie
    config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
    
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/api/**", config); // 仅对/api路径生效
    
    return new CorsFilter(source);
}

六、注意事项

  1. 生产环境禁止allowedOrigins("*"):若需允许所有域名,应改用allowedOriginPatterns("*")并配合allowCredentials(true)。
  2. Cookie 与认证:若需携带 Cookie,需同时设置:后端:Access-Control-Allow-Credentials: true 且 allowedOrigins 不能为*。前端:fetch或axios中设置withCredentials: true。
  3. 预检请求(Preflight):复杂请求(如 PUT、DELETE、带自定义头)会先发送 OPTIONS 请求,需确保服务器正确响应。

总结

  • 开发环境:优先使用前端代理。
  • Spring 项目:推荐@CrossOrigin注解或全局配置。
  • 非 Spring 项目:使用 Filter 配置。
  • 生产环境:推荐 Nginx 反向代理或细粒度 CORS 配置。
  • 兼容性需求:可使用 JSONP(仅 GET 请求)。

相关文章

7种超轻量级的Linux发行版,能够帮助你找到适合自己的操作系统

Linux是一种非常受欢迎的开源操作系统,而且有许多版本可以选择。有时候,你需要一种超轻量级的Linux发行版,它可以在资源有限的设备上运行,并且能够快速启动。本文将介绍7种超轻量级的Linux发行版...

据说是可以替代 Windows 的 5个 Linux 发行版

现如今有数以千计的 Linux 发行版可供您使用,然而人们却无法选择一个完美的操作系统来替代 Windows。 使用 Windows 时,傻瓜都能操作自如,同样的方法却不适用于 Linux。在这里,您...

【Vue3 基础】05.组件化(组件使用vuex)

这是 Vue3 + Vite + Pinia +TS + Element-Plus 实战系列文档。最近比较忙没什么时间写文章,争取早日把这个系列完结吧~生命周期和模板引用在本章之前,我们通过响应式 a...

「 VUE3 + TS + Vite 」父子组件间如何通信?

组件之间传值,大家都很熟悉,涉及到 VUE3 +TS 好多同学就无从下手了,所以分享这篇文章,希望看完后提起 VUE3+TS 能够不慌不忙。平时使用的函数如:ref、reactive、watch、co...

vue3源码分析——实现组件通信provide,inject

引言<<往期回顾>>vue3源码分析——rollup打包monorepovue3源码分析——实现组件的挂载流程vue3源码分析——实现props,emit,事件处理等vue3源...

vue 3 学习笔记 (八)——provide 和 inject 用法及原理

在父子组件传递数据时,通常使用的是 props 和 emit,父传子时,使用的是 props,如果是父组件传孙组件时,就需要先传给子组件,子组件再传给孙组件,如果多个子组件或多个孙组件使用时,就需要传...