SpringBoot和前端Vue的跨域問題及解決方案
一、為什么會出現(xiàn)跨域問題
出于瀏覽器的同源策略限制。同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響??梢哉fWeb是構(gòu)建在同源策略基礎(chǔ)之上的,瀏覽器只是針對同源策略的一種實現(xiàn)。同源策略會阻止一個域的。javascript腳本和另外一個域的內(nèi)容進行交互。所謂同源(即指在同一個域)就是兩個頁面具有相同的協(xié)議(protocol),主機(host)和端口號(port)。
二、什么是跨域?
要了解什么是跨域,我們先說一下同源的概念。同源,是指協(xié)議、域名、端口都相同。
例如:http://192.168.0.1:8080與https://192.168.3.1:8080不是同源,因為協(xié)議不同,第一個冒號前面的為協(xié)議,中間的為域名,第二個冒號后面的為端口,只要滿足有一處不同,則就不是同源。
所謂跨域就是從 A 向 B 發(fā)請求,如若他們的地址協(xié)議、域名、端口都不相同,直接訪問就會造成跨域問題,跨域是非常常見的現(xiàn)象!請求是跨域的但并不一定會報錯,普通的圖片請求。css文件請求是不會報錯的。報錯的條件是瀏覽器的同源策略,且發(fā)送Ajax請求,跨域是客戶端問題。
類似于如下:
三、常見的跨域場景
四、如何解決跨域?
1.JSONP
jsonp的原理就是利用<script>
標簽沒有跨域限制,通過<script>
標簽src屬性,發(fā)送帶有callback參數(shù)的GET請求,服務(wù)端將接口返回數(shù)據(jù)拼湊到callback函數(shù)中,返回給瀏覽器,瀏覽器解析執(zhí)行,從而前端拿到callback函數(shù)返回的數(shù)據(jù)。
jsonp的缺點:只能發(fā)送get一種請求。
2.CORS
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。
CORS需要瀏覽器和服務(wù)器同時支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。
瀏覽器將CORS跨域請求分為簡單請求和非簡單請求。
只要同時滿足一下兩個條件,就屬于簡單請求
(1)使用下列方法之一:
- head
- get
- post
(2)請求的Heder是
- Accept
- Accept-Language
- Content-Language
- Content-Type: 只限于三個值:application/x-www-form-urlencoded、multipart/form-data、text/plain
不同時滿足上面的兩個條件,就屬于非簡單請求。瀏覽器對這兩種的處理,是不一樣的。
3.nginx反向代理接口跨域
可以將前端項目部署到和接口同源的當前本地的服務(wù)器上。在vue.config.js 中進行代理配置,假設(shè)當我訪問 http://localhost:9528/api/login 時會轉(zhuǎn)換為間接訪問 http://localhost:3000/api/login
devServer: { // 其他代碼省略。。。。。 // 代理配置 proxy: { // 代理服務(wù)器,當請求的網(wǎng)址是http://localhost:3000的時候,會轉(zhuǎn)成http://192.168.80.115:3000 // /api 是 看接口文檔所寫的,每當訪問本地的/api接口時,會轉(zhuǎn)化為訪問真實的服務(wù)器 '/api': { target: 'http://localhost:3000' // 我們要代理的真實接口地址 } }
4.web sockets
它是一種瀏覽器的API,它的目標是在一個單獨的持久連接上提供全雙工、雙向通信。(同源策略對web sockets不適用)web sockets原理:在JS創(chuàng)建了web socket之后,會有一個HTTP請求發(fā)送到瀏覽器以發(fā)起連接。取得服務(wù)器響應后,建立的連接會使用HTTP升級從HTTP協(xié)議交換為web sockt協(xié)議。 只有在支持web socket協(xié)議的服務(wù)器上才能正常工作。
屬性:
5.node.js中間件代理跨域
node中間件實現(xiàn)跨域代理,原理大致與nginx相同,都是通過啟一個代理服務(wù)器,實現(xiàn)數(shù)據(jù)的轉(zhuǎn)發(fā),也可以通過設(shè)置cookieDomainRewrite參數(shù)修改響應頭中cookie中域名,實現(xiàn)當前域的cookie寫入,方便接口登錄認證。
1)非vue框架的跨域
使用node + express + http-proxy-middleware搭建一個proxy服務(wù)器。
前端代碼:
var xhr = new XMLHttpRequest(); // 前端開關(guān):瀏覽器是否讀寫cookie xhr.withCredentials = true; // 訪問http-proxy-middleware代理服務(wù)器 xhr.open('get', 'http://www.domain1.com:3000/login?user=admin', true); xhr.send();
中間件服務(wù)器代碼:
var express = require('express'); var proxy = require('http-proxy-middleware'); var app = express(); app.use('/', proxy({ // 代理跨域目標接口 target: 'http://www.domain2.com:8080', changeOrigin: true, // 修改響應頭信息,實現(xiàn)跨域并允許帶cookie onProxyRes: function(proxyRes, req, res) { res.header('Access-Control-Allow-Origin', 'http://www.domain1.com'); res.header('Access-Control-Allow-Credentials', 'true'); }, // 修改響應信息中的cookie域名 cookieDomainRewrite: 'www.domain1.com' // 可以為false,表示不修改 })); app.listen(3000); console.log('Proxy server is listen at port 3000...');
2)vue框架的跨域
node + vue + webpack + webpack-dev-server搭建的項目,跨域請求接口,直接修改webpack.config.js配置。開發(fā)環(huán)境下,vue渲染服務(wù)和接口代理服務(wù)都是webpack-dev-server同一個,所以頁面與代理接口之間不再跨域。
webpack.config.js部分配置:
module.exports = { entry: {}, module: {}, ... devServer: { historyApiFallback: true, proxy: [{ context: '/login', target: 'http://www.domain2.com:8080', // 代理跨域目標接口 changeOrigin: true, secure: false, // 當代理某些https服務(wù)報錯時用 cookieDomainRewrite: 'www.domain1.com' // 可以為false,表示不修改 }], noInfo: true } }
五、SpringBoot跨域問題的解決
在Springboot項目里加上這個配置文件CorsConfig.java
,重啟之后即可實現(xiàn)跨域訪問,前端無需再配置跨域。
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 { // 當前跨域請求最大有效時長。這里默認1天 private static final long MAX_AGE = 24 * 60 * 60; @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); // 1 設(shè)置訪問源地址 corsConfiguration.addAllowedHeader("*"); // 2 設(shè)置訪問源請求頭 corsConfiguration.addAllowedMethod("*"); // 3 設(shè)置訪問源請求方法 corsConfiguration.setMaxAge(MAX_AGE); source.registerCorsConfiguration("/**", corsConfiguration); // 4 對接口配置跨域設(shè)置 return new CorsFilter(source); } }
六、前端跨域解決
request.js用來請求數(shù)據(jù),封裝的代碼如下:
import axios from 'axios' const request = axios.create({ baseURL: '/api', // 注意??! 這里是全局統(tǒng)一加上了 '/api' 前綴,也就是說所有接口都會加上'/api'前綴在,頁面里面寫接口的時候就不要加 '/api'了,否則會出現(xiàn)2個'/api',類似 '/api/api/user'這樣的報錯,切記?。?! timeout: 5000 }) // request 攔截器 // 可以自請求發(fā)送前對請求做一些處理 // 比如統(tǒng)一加token,對請求參數(shù)統(tǒng)一加密 request.interceptors.request.use(config => { config.headers['Content-Type'] = 'application/json;charset=utf-8'; // config.headers['token'] = user.token; // 設(shè)置請求頭 return config }, error => { return Promise.reject(error) }); // response 攔截器 // 可以在接口響應后統(tǒng)一處理結(jié)果 request.interceptors.response.use( response => { let res = response.data; // 如果是返回的文件 if (response.config.responseType === 'blob') { return res } // 兼容服務(wù)端返回的字符串數(shù)據(jù) if (typeof res === 'string') { res = res ? JSON.parse(res) : res } return res; }, error => { console.log('err' + error) // for debug return Promise.reject(error) } ) export default request
vue.config.js:
// 跨域配置 module.exports = { devServer: { //記住,別寫錯了devServer//設(shè)置本地默認端口 選填 port: 9876, proxy: { //設(shè)置代理,必須填 '/api': { //設(shè)置攔截器 攔截器格式 斜杠+攔截器名字,名字可以自己定 target: 'http://localhost:9999', //代理的目標地址 changeOrigin: true, //是否設(shè)置同源,輸入是的 pathRewrite: { //路徑重寫 '^/api': '' //選擇忽略攔截器里面的內(nèi)容 } } } } }
七、前后端都跨域
如果后端設(shè)置了跨域配置,則使用下面的request.js 代碼:
import axios from 'axios' const request = axios.create({ baseURL: 'http://localhost:9090', // 注意?。?這里是全局統(tǒng)一加上了 后端接口前綴 前綴,后端必須進行跨域配置! timeout: 5000 }) // request 攔截器 // 可以自請求發(fā)送前對請求做一些處理 // 比如統(tǒng)一加token,對請求參數(shù)統(tǒng)一加密 request.interceptors.request.use(config => { config.headers['Content-Type'] = 'application/json;charset=utf-8'; // config.headers['token'] = user.token; // 設(shè)置請求頭 return config }, error => { return Promise.reject(error) }); // response 攔截器 // 可以在接口響應后統(tǒng)一處理結(jié)果 request.interceptors.response.use( response => { let res = response.data; // 如果是返回的文件 if (response.config.responseType === 'blob') { return res } // 兼容服務(wù)端返回的字符串數(shù)據(jù) if (typeof res === 'string') { res = res ? JSON.parse(res) : res } return res; }, error => { console.log('err' + error) // for debug return Promise.reject(error) } ) export default request
?小結(jié)
以上就是對解決SpringBoot和前端Vue的跨域問題簡單的概述,現(xiàn)在我們的項目就更加的趨于完美了,也提升了我們對于編程的能力和思維!
到此這篇關(guān)于解決SpringBoot和前端Vue的跨域問題的文章就介紹到這了,更多相關(guān)springboot vue跨域內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在SpringBoot中注入RedisTemplate實例異常的解決方案
這篇文章主要介紹了在SpringBoot中注入RedisTemplate實例異常的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01在Linux上搭建一個Java部署環(huán)境的詳細步驟
這篇文章主要介紹了在Linux上搭建一個Java部署環(huán)境,安裝jdk有很多種方式,但是我們這里推薦的是使用yum直接安裝openjdk,本文給大家介紹的非常詳細,需要的朋友可以參考下2023-01-01Spring Boot命令行啟動添加參數(shù)的三種方式
在命令行中,常見的參數(shù)可以分為三類:選項參數(shù)、非選項參數(shù)和系統(tǒng)參數(shù),本文就來介紹一下Spring Boot命令行三種參數(shù)形式,感興趣的可以了解一下2023-09-09JAVA內(nèi)存模型和Happens-Before規(guī)則知識點講解
在本篇文章里小編給大家整理的是一篇關(guān)于JAVA內(nèi)存模型和Happens-Before規(guī)則知識點內(nèi)容,有需要的朋友們跟著學習下。2020-11-11解決@ServerEndpoint不能注入@Autowired的問題
這篇文章主要介紹了解決@ServerEndpoint不能注入@Autowired的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05