在成功搭建好DRF(Django rest framework)的Blog的backend后,昨天開始搭建Vue3+axios+pinia+element_plus的前臺服務(wù).
開始一切順利,到第一個axios的get處理的時候,出現(xiàn)了錯誤.
axios相關(guān)的代碼如下:
加載vue-axios和axios模塊
npm install --save vue-axios axios
axios初始化(main.ts)
app.use(VueAxios, axios); axios.defaults.baseURL = "http://localhost:8000/api"; //axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*'; // axios.defaults.headers.common['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'; //axios.defaults.headers.common['Access-Control-Allow-Headers'] = 'X-Requested-With,content-type'; //axios.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded'; app.provide('axios',app.config.globalProperties.axios)
?文章來源地址http://www.zghlxwxcb.cn/news/detail-420497.html
axios取數(shù)據(jù)
在Pinia的Store中調(diào)用axios.get方法取得Backend端的Tag數(shù)據(jù)
export const useBlogData = defineStore("blogData",()=>{ const axios:any = inject('axios'); const tagsMenu = ref([]) axios.get('/tags').then((response:{data:any})=>{ tagsMenu.value = response.data.results; }) return {tagsMenu} })
目前的代碼不嚴謹,沒有進行錯誤處理.
出現(xiàn)跨域錯誤(CORS)
在Chrome的開發(fā)者模式下可以看到,報告Cors錯誤(CORS policy: No ‘Access-Control-Allow-Orign’ header is present on requested resource.
?發(fā)現(xiàn)錯誤后,急急慢慢去Google解決方案, 了解CORS的出錯的原因以及可能的解決方案,
CORS跨域錯誤的原因
MDN上有文章詳細說明了CORS出錯的原因以及Client Server端的請求與應(yīng)答之間的關(guān)系.https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
簡單的來說,我們的backend與frontend服務(wù)是分開的, Browser在執(zhí)行Vue相關(guān)的處理的時候,回交叉訪問不同的服務(wù)器,這樣對于服務(wù)器來說可能會出現(xiàn)安全漏洞,所以會對這種請求進行拒絕操作.
關(guān)于CORS的中文的說明在Google云上有一篇文章說明https://cloud.google.com/storage/docs/cross-origin?hl=zh-cn, 我覺得還是MDN上講解的更透徹.
CORS跨域錯誤的解決方案
在Google、StackOverflow上各種查詢最終得出應(yīng)該是兩種解決方案:
Backend Server端的解決方案
Django提供了Backend Server端的解決方案,在前面的文章中已經(jīng)提到過處理方法:
參考Django的CORS Header模塊說明?https://pypi.org/project/django-cors-headers/
安裝django-cors-headers, 修改setting.py, 其中需要注意的是MiddleWare相關(guān)的修改
MIDDLEWARE = [ ..., "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", ..., ]
corsheaders.middleware.CorsMiddleware的位置盡量向上,要在這個CommonMiddleware前面,否則也可能會出現(xiàn)CORS錯誤.
我的Backend端一直有這樣的處理,檢查代碼,加入各種奇怪的配置,還是繼續(xù)出錯,苦惱很長時間.
Frontend Sever的解決方案
Frontend Server的解決方案就是在Frontend Server上設(shè)置Proxy, 將Vue的axios發(fā)起的get請求不直接發(fā)給Backend Server,發(fā)給Frontend, Frontend通過Proxy的配置轉(zhuǎn)給Backend Server,從而避免了CORS的問題.
我的開發(fā)環(huán)境使用的是Vite, Google等上面有說修改vue.config.ts的,這個主要是面向Vue-CLI的,在Vite上修改的vite.config.ts
server:{ port:8080, proxy:{ '/api':'http://127.0.0.1:8000' } },
加入proxy代理, 如上所示我的backend端的rest api的url是http://127.0..0.1:8000/api ,加入上述處理后 Frontend對應(yīng)的http://localhost:8080/api上的請求會通過proxy轉(zhuǎn)移到backend上
在axios的處理中,將面向backend處理baseurl設(shè)置為frontend上
axios.defaults.baseURL = "http://localhost:8080/api";
通過Frontend Server的解決方案可以成功解決目前碰見的CORS問題.
為什么Backend Server端的解決方案沒有解決問題呢?
雖然通過Frontend Server的解決方案繞過了CORS錯誤,但是為什么Backend Server端的解決方案就是不行呢??
Google、Stackoverflow給出了在http的header上加Access-Control-Allow-Origin的解題過程.
我在代碼中加入headers相關(guān)的處理
axios.defaults.baseURL = "http://localhost:8000/api"; axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
Chrome上的錯誤出現(xiàn)了新的情況:變成 access-control-allow-orign is not allowed by Access-Control-Headers的錯誤
在Chrome 網(wǎng)絡(luò)中可以看見多了一個axios的請求成功了, axios發(fā)了一個preflight的請求去Backend預(yù)檢測是否可以跨域請求
發(fā)現(xiàn)preflight請求成功了,我以為自己離解決問題近了一步,現(xiàn)在反思起了其實是退步了. 之后一直陷在這個地方找不到原因,各種Server端的配置,Frontend端的配置都不能成功.
在Stackoverflow上發(fā)現(xiàn)有人說問題就是結(jié)尾少了一個“/”,?我在axios的get請求“/tags”加入“/tags/”, 仍然還是出錯.一度錯過了這個問題的解決方案.
解決問題
折騰一晚上睡覺起了,再仔細的看MDN中的文章, 文章中說對于Simple Request(get、post、put、delete)的請求是不需要發(fā)送preflight請求的.現(xiàn)在看這個錯誤的意思就是access-control-allow-orgin這個header字段不被Backend Server支持,Backend拒絕了訪問. 看不到解決方案決定回到起點,將header相關(guān)的處理去掉,將axios的代碼回歸到
axios.defaults.baseURL = "http://localhost:8000/api"; //axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
通過curl -i -L查看請求的結(jié)果,發(fā)現(xiàn)Backend端其實已經(jīng)取得了tags數(shù)據(jù),并返回給Broswer,但是結(jié)果確被重定向了,會出現(xiàn)301錯誤
這時候想起看過的關(guān)于請求結(jié)尾需要加“/”的處理,想明白了可能就是這個“/”導(dǎo)致的錯誤.在axios的get請求中將“/tags”,修改為“/tags/”.問題得到解決.
修改代碼?
export const useBlogData = defineStore("blogData",()=>{ const axios:any = inject('axios'); const tagsMenu = ref([]) axios.get('/tags/').then((response:{data:any})=>{ tagsMenu.value = response.data.results; }) return {tagsMenu} })
最終的解決方案: Backend的cors header模塊 + “/”解決問題.
還有一個需要注意的地方是,在每次修改代碼后,最好是將之前的頁面關(guān)掉,重開避免Cache引起的干擾.
?文章來源:http://www.zghlxwxcb.cn/news/detail-420497.html
?
到了這里,關(guān)于漏了一個“/”導(dǎo)致的跨域錯誤(CORS)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!