vue2/3,Spring Boot以及生产环境跨域解决方案

vue2和vue3跨域解决方案

Vue 2 (基于 Webpack) 的跨域解决方案

1. 创建或编辑 vue.config.js 文件

Vue CLI为Webpack项目提供了简单的代理配置方式。你可以通过创建或编辑项目的根目录下的 vue.config.js 文件来设置开发服务器的代理规则:

javascript 复制代码
// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': { // 代理路径前缀
        target: 'http://backend.example.com', // 后端API的地址
        changeOrigin: true,                   // 更改请求源
        pathRewrite: { '^/api': '' },         // 重写路径,去掉/api前缀
        secure: false,                        // 如果后端是HTTPS,则设置为true,默认false
        logLevel: 'debug'                     // 设置日志级别,方便调试
      }
    }
  }
};

2. 修改前端请求代码

确保你的前端请求都通过 /api 前缀发送,这样它们会被正确代理到后端服务器:

javascript 复制代码
// 在Vue组件或API服务中
import axios from 'axios';

export function fetchDepartments() {
  return axios.get('/api/depts')
    .then(response => response.data)
    .catch(error => console.error('There was an error!', error));
}

Vue 3 (基于 Vite) 的跨域解决方案

Vite使用了一种不同的方式来处理开发服务器的代理配置。它没有像Webpack那样内置的代理配置选项,但可以通过修改 vite.config.js 来实现相同的功能。

使用 Vite 的代理配置

1. 创建或编辑 vite.config.js 文件

你需要在 vite.config.js 中定义一个 server.proxy 属性:

javascript 复制代码
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  server: {
    proxy: {
      '/api': {
        target: 'http://backend.example.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
});

2. 修改前端请求代码

同Vue 2一样,确保所有对后端的请求都通过 /api 前缀来发送:

javascript 复制代码
// 在Vue组件或API服务中
import axios from 'axios';

export function fetchDepartments() {
  return axios.get('/api/depts')
    .then(response => response.data)
    .catch(error => console.error('There was an error!', error));
}

Spring Boot 中的 CORS 配置详解

方法 1:使用 @CrossOrigin 注解(局部配置)

@CrossOrigin 注解是最简单的方式,适用于需要为特定控制器或方法启用CORS的情况。你可以通过在控制器类或方法上添加这个注解来实现。

局部配置示例

java 复制代码
// src/main/java/com/example/demo/controller/MyController.java
package com.example.demo.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
import java.util.Arrays;
import java.util.List;

@RestController
@RequestMapping("/api/depts")
@CrossOrigin(origins = "https://example.com", maxAge = 3600) // 允许的源及缓存时间
public class MyController {

    @GetMapping
    public ResponseEntity<List<String>> getDepts() {
        List<String> depts = Arrays.asList("HR", "Finance", "IT");
        return ResponseEntity.ok(depts);
    }
}

注意事项

  • origins:指定允许的源。
  • maxAge:预检请求的结果可以被缓存的时间(以秒为单位)。
  • allowedHeaders:可选,指定允许的HTTP头。
  • methods:可选,指定允许的HTTP方法。
  • exposedHeaders:可选,指定哪些响应头可以暴露给浏览器。
  • allowCredentials :是否允许凭证(如Cookies)。如果设置为 true,则不能使用通配符 * 作为源。

完整注解参数

java 复制代码
@CrossOrigin(
    origins = {"https://example.com"}, 
    methods = {RequestMethod.GET, RequestMethod.POST},
    allowedHeaders = {"Authorization", "Content-Type"},
    exposedHeaders = {"X-Custom-Header"},
    allowCredentials = "true",
    maxAge = 3600
)

方法 2:全局配置 CORS(WebMvcConfigurer)

如果你想要为所有端点配置CORS,或者定义多个CORS配置,可以通过实现 WebMvcConfigurer 接口并重写 addCorsMappings 方法来进行全局配置。

全局配置示例

java 复制代码
// src/main/java/com/example/demo/config/WebConfig.java
package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 匹配所有路径
                .allowedOrigins("https://example.com") // 允许的源
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法
                .allowedHeaders("*") // 允许的HTTP头
                .allowCredentials(true) // 是否允许凭证
                .maxAge(3600); // 预检请求结果缓存时间(秒)
    }
}

注意事项

  • allowedOrigins :指定允许的源,可以是一个具体的URL,也可以是通配符 * 表示允许所有源。但是,如果你启用了凭证共享 (allowCredentials=true),则不能使用通配符 *
  • allowedMethods:指定允许的HTTP方法。
  • allowedHeaders:指定允许的HTTP头。
  • allowCredentials :如果设置为 true,则意味着响应将包含 Access-Control-Allow-Credentials 头,这会告诉浏览器是否允许发送凭证信息(例如cookies)。如果启用了凭证,则不能将 allowedOrigins 设置为 *
  • maxAge:预检请求的结果可以被缓存的时间(以秒为单位)。

多路径配置示例

如果你需要为不同路径设置不同的CORS规则,可以在 addCorsMappings 方法中注册多个映射:

java 复制代码
@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/api/**")
            .allowedOrigins("https://example.com")
            .allowedMethods("GET", "POST")
            .allowedHeaders("Authorization", "Content-Type")
            .allowCredentials(true)
            .maxAge(3600);

    registry.addMapping("/admin/**")
            .allowedOrigins("https://admin.example.com")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("*")
            .allowCredentials(false)
            .maxAge(3600);
}

方法 3:通过 CorsFilter 配置

对于更复杂的场景,比如你需要对不同的路径应用不同的CORS规则,或者你希望在应用程序启动时就注册CORS过滤器,你可以创建一个 CorsConfigurationSource 并注册一个 CorsFilter

自定义 CorsFilter 示例

java 复制代码
// src/main/java/com/example/demo/config/CorsConfig.java
package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        // Path 1: /api/*
        CorsConfiguration apiConfig = new CorsConfiguration();
        apiConfig.setAllowCredentials(true);
        apiConfig.addAllowedOrigin("https://example.com");
        apiConfig.addAllowedHeader("Authorization");
        apiConfig.addAllowedHeader("Content-Type");
        apiConfig.addAllowedMethod("GET");
        apiConfig.addAllowedMethod("POST");
        source.registerCorsConfiguration("/api/**", apiConfig);

        // Path 2: /admin/*
        CorsConfiguration adminConfig = new CorsConfiguration();
        adminConfig.setAllowCredentials(false);
        adminConfig.addAllowedOrigin("https://admin.example.com");
        adminConfig.addAllowedHeader("*");
        adminConfig.addAllowedMethod("*");
        source.registerCorsConfiguration("/admin/**", adminConfig);

        return new CorsFilter(source);
    }
}

多路径配置示例

如果你有多个路径需要不同的CORS规则,可以在 UrlBasedCorsConfigurationSource 中注册多个配置:

java 复制代码
@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

    // Path 1: /api/*
    CorsConfiguration apiConfig = new CorsConfiguration();
    apiConfig.setAllowCredentials(true);
    apiConfig.addAllowedOrigin("https://example.com");
    apiConfig.addAllowedHeader("Authorization");
    apiConfig.addAllowedHeader("Content-Type");
    apiConfig.addAllowedMethod("GET");
    apiConfig.addAllowedMethod("POST");
    source.registerCorsConfiguration("/api/**", apiConfig);

    // Path 2: /admin/*
    CorsConfiguration adminConfig = new CorsConfiguration();
    adminConfig.setAllowCredentials(false);
    adminConfig.addAllowedOrigin("https://admin.example.com");
    adminConfig.addAllowedHeader("*");
    adminConfig.addAllowedMethod("*");
    source.registerCorsConfiguration("/admin/**", adminConfig);

    return new CorsFilter(source);
}

高级配置选项

1. 处理凭证共享

当你需要处理凭证(如Cookies)时,确保正确设置了 allowCredentialsallowedOrigins。记住,如果启用了凭证共享,你不能使用通配符 * 作为允许的源。

java 复制代码
config.setAllowCredentials(true);
config.addAllowedOrigin("https://example.com"); // 必须明确指定源
2. 处理复杂头部

有时你需要处理特定的HTTP头部,而不是简单的通配符。你可以通过 setAllowedHeaders 方法来指定允许的头部。

java 复制代码
config.addAllowedHeader("Authorization");
config.addAllowedHeader("Content-Type");
3. 处理多种来源

如果你有多个允许的来源,可以使用 setAllowedOrigins 方法来添加多个源。

java 复制代码
config.addAllowedOrigin("https://example.com");
config.addAllowedOrigin("https://anotherdomain.com");
4. 处理预检请求

预检请求(Preflight Requests)是在某些跨域请求之前由浏览器自动发送的,用于检查服务器是否允许实际请求。你可以通过 setAllowCredentialssetMaxAge 来控制这些行为。

java 复制代码
config.setAllowCredentials(true);
config.setMaxAge(3600L); // 缓存预检请求结果的时间(秒)
5. 暴露特定响应头

有时候你需要让客户端能够访问某些特定的响应头。你可以通过 setExposedHeaders 方法来指定这些响应头。

java 复制代码
config.setExposedHeaders(Arrays.asList("X-Custom-Header"));

生产环境下的解决方案

1. 使用 Nginx 反向代理

Nginx 是一个高性能的HTTP和反向代理服务器,它可以帮助你将前端请求转发到后端API服务器,同时处理跨域问题。通过这种方式,你可以确保所有的请求都来自同一个域名,从而避免浏览器的同源策略限制。

Nginx 配置示例

假设你的前端应用部署在 http://example.com,而后端API位于 http://backend.example.com。你可以使用Nginx来设置反向代理:

javascript 复制代码
# /etc/nginx/sites-available/example.com
server {
    listen 80;
    server_name example.com;

    location / {
        # 将所有前端静态资源请求指向Vue构建的静态文件目录
        root /var/www/html/dist;
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        # 将/api/开头的请求转发给后端API服务器
        proxy_pass http://backend.example.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

步骤:

  1. 安装 Nginx(如果尚未安装):

    bash 复制代码
    sudo apt update
    sudo apt install nginx
  2. 配置 Nginx

    • 创建或编辑 /etc/nginx/sites-available/example.com 文件。
    • 使用上述配置示例进行修改,确保路径和域名正确。
  3. 启用站点配置

    bash 复制代码
    sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
  4. 测试配置并重启 Nginx

    bash 复制代码
    sudo nginx -t
    sudo systemctl restart nginx
  5. 部署前端静态文件

    • 将Vue构建后的静态文件放置在 /var/www/html/dist 目录下。
  6. 确保后端API服务器正常运行

    • 确认 http://backend.example.com 可以访问,并且API服务正常工作。

2. 前后端部署在同一域名下

如果可能的话,将前后端部署在同一域名下是解决跨域问题的最佳实践之一。这样做可以完全避免跨域问题,因为所有请求都来自同一源。

示例:

  • 前端 :部署在 https://example.com
  • 后端API :部署在 https://api.example.com

如果你使用的是子域名(如 api.example.com),你可以通过DNS配置和SSL证书来确保它们被视为同一源。另外,也可以考虑将API路由集成到主域名中(例如 https://example.com/api)。

相关推荐
seventeennnnn2 小时前
谢飞机的Java高级开发面试:从Spring Boot到分布式架构的蜕变之旅
spring boot·微服务架构·java面试·分布式系统·电商支付
超级小忍4 小时前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
时间会给答案scidag4 小时前
报错 400 和405解决方案
vue.js·spring boot
Wyc724095 小时前
SpringBoot
java·spring boot·spring
ladymorgana6 小时前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
GJCTYU8 小时前
spring中@Transactional注解和事务的实战理解附代码
数据库·spring boot·后端·spring·oracle·mybatis
风象南9 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
写不出来就跑路10 小时前
暑期实习感悟与经验分享:从校园到职场的成长之路
java·开发语言·经验分享·spring boot
程序员张314 小时前
Maven编译和打包插件
java·spring boot·maven
灵犀学长15 小时前
EasyExcel之SheetWriteHandler:解锁Excel写入的高阶玩法
spring boot·excel