Handling CORS in Spring Boot and Vue3: Concepts, Code, and Demo
This article explains the concept of Cross‑Origin Resource Sharing (CORS), demonstrates how to identify cross‑origin requests, and provides a complete Spring Boot backend configuration together with Vue3/Axios frontend code to solve CORS issues in a full‑stack web application.
Cross‑Origin Resource Sharing (CORS) is a browser security mechanism that blocks requests when the protocol, domain, or port differ between the client and server; such requests are considered cross‑origin.
The article first defines CORS, illustrates how to determine whether a URL is cross‑origin with examples, and shows a table summarizing several URLs and the reasons they are or are not cross‑origin.
URL Is Cross‑Origin Reason http://www.mysite.com Yes Domain differs https://www.fullstack.com Yes Protocol differs http://www.fullstack.com:81 Yes Port differs http://www.fullstack.com/index.html No Protocol, domain, and port are the same
Next, the tutorial walks through a three‑part implementation:
1. Frontend setup – Create a Vue3 project, install axios , and add a request utility ( src/utils/request.js ) with custom configuration, request/response interceptors, and cookie handling:
import axios from 'axios'
// Create axios instance with custom config
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8081',
timeout: 10000,
withCredentials: true, // send cookies for cross‑origin
headers: { 'Content-Type': 'application/json;charset=UTF-8' }
})
// Request interceptor
service.interceptors.request.use(config => {
// add token or other headers here
return config
}, error => Promise.reject(error))
// Response interceptor
service.interceptors.response.use(response => {
return response.data
}, error => {
console.error('API Error:', error.response?.status, error.message)
return Promise.reject({ status: error.response?.status, message: error.message || '请求失败' })
})
export default service2. Vue components – The root component ( src/App.vue ) imports the request utility and a demo component; the demo component ( src/components/ApiDemo.vue ) fetches data from /api/data , shows loading, error, and the returned JSON, and includes an automatic retry after 3 seconds.
<script setup>
import { ref, onMounted } from 'vue'
import api from '@/utils/request'
const responseData = ref(null)
const loading = ref(false)
const error = ref(null)
const fetchData = async () => {
loading.value = true
error.value = null
try {
const data = await api.get('/api/data')
responseData.value = data
} catch (err) {
error.value = `错误代码 ${err.status || 500}: ${err.message}`
console.error('API请求失败:', err)
} finally {
loading.value = false
}
}
onMounted(async () => {
await fetchData()
if (error.value) {
setTimeout(fetchData, 3000) // retry after 3 seconds
}
})
</script>
<template>
<div class="demo-container">
<h2>API 数据演示</h2>
<div v-if="loading" class="loading-state">
<div class="spinner"></div> 数据加载中...
</div>
<div v-else-if="error" class="error-state">❌ {{ error }}
<button @click="fetchData" class="retry-btn">重试</button>
</div>
<div v-else class="data-box">
<pre>{{ JSON.stringify(responseData, null, 2) }}</pre>
</div>
</div>
</template>3. Backend configuration – In application.yml set the server port to 8081, then create a Spring Boot controller that returns a simple string, and configure a global CORS filter ( CorsConfig ) to allow the Vue dev server ( http://localhost:5173 ) with all methods, any headers, credentials, and a max age of 3600 seconds:
package com.fullstack.commerce.user.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class DataController {
@GetMapping("/data")
public ResponseEntity
getData() {
return ResponseEntity.ok("跨域请求成功!数据来自Spring Boot");
}
}
package com.fullstack.commerce.user.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 CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5173") // front‑end address
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}After restarting the Spring Boot application and running npm run dev for the Vue project, accessing http://localhost:5173/ initially shows a CORS error; once the backend CORS configuration is applied, the request succeeds and the data is displayed.
The article concludes that CORS is a common interview and development topic, and that Spring Boot together with proper frontend setup provides a straightforward solution, encouraging readers to try the example and reach out for any questions.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.