axios解決跨域問題

最近把我本身的網站升級生成先後端分離的項目(vue+springBoot),不可避免的就遇到了跨域問題。從中學到了許多知識,隨便分享出來,也鞏固下所學。前端

     談到跨域,首先得了解CORS(Cross origin resource sharing) 跨域資源共享,它是w3c的一個標準,是一份瀏覽器技術規範,提供了web服務從不一樣網域傳來沙盒腳本的方法,以免瀏覽器的同源策略,是比JSONP模式的高級版。JSONP只支持GET請求方式,而CORS除了GET請求方式之外也支持其餘的HTTP請求。CORS容許瀏覽器發送跨域服務器,發出XMLHttpRequest請求,從而克服AJAX只能同源請求。(想要了解爲何有跨域問題的產生,請了解瀏覽器的同源策略)vue

    瀏覽器發出CORS請求,須要對請求頭增長一些信息,服務器會根據這些信息來是否決定贊成此次請求。須要的頭信息字段以下:java

    (1)Access-Control-Allow-Originios

              這個頭信息字段是必須的。它指定容許進入來源的域名、ip+端口號 。 若是值是 ‘*’ ,表示接受任意的域名請求,這個方式不推薦,主要是由於其不安全,並且由於若是瀏覽器的請求攜帶了cookie信息,會發生下圖錯誤:web

 

    (2) Access-Control-Allow-Credentialsajax

                該字段是可選的。它設置是否能夠容許發送cookie,true表示cookie包含在請求中,false則相反,默認爲false。若是項目須要cookie就得設置該字段了。CORS請求默認不發送Cookie和HTTP認證信息的,因此在此基礎上同時也須要在前端設置(以axios爲例): axios.defaults.withCredentials = truespring

    (3)Access-Control-Max-Agevue-router

                該字段是可選的。用於配置CORS緩存時間,即本次請求的有效期,單位爲秒。element-ui

    (4)Access-Control-Allow-Methodsjson

              該字段可選。設置容許的請求方法。

     (5)Access-Control-Allow-Headers

             該字段可選。設置容許的請求頭信息

      (...)其餘請參考相關資料

       提示:這些設置在後端的攔截器中設置。
 

     對於axios,它是vue2提倡使用的輕量版的ajax。它是基於promise的HTTP庫。它會從瀏覽器中建立XMLHttpRequests。若是對axios不太瞭解,能夠先看下這個兩個博客:https://www.kancloud.cn/yunye/axios/234845    和   https://www.jianshu.com/p/7a9fbcbb1114

     瞭解到這些以後就能夠解決跨域問題啦, 詳細代碼以下:

    (1) vue.js

      

import axios from 'axios'
import store from '../store'
import { getToken } from '@/utils/auth'
import { Message, MessageBox } from 'element-ui'
// 每次請求攜帶cookies信息
axios.defaults.withCredentials = true
// 建立axios實例
const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url
timeout: 15000 // 請求超時時間
})
// request攔截器
service.interceptors.request.use(config => {
console.log(store.getters.token)
if (store.getters.token) {
console.log(getToken())
config.headers['X-Token'] = getToken() // 讓每一個請求攜帶自定義token 請根據實際狀況自行修改
var token = getToken()
Object.assign(config.headers, { 'token': token })
}
return config
}, error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
})
// respone攔截器
service.interceptors.response.use(
response => {
/**
* code爲非20000是拋錯 可結合本身業務進行修改
*/
console.log(response.data)
const res = response.data
if (res.code !== 20000) {
Message({
message: res.message,
type: 'error',
duration: 5 * 1000
})

// 50008:非法的token; 50012:其餘客戶端登陸了; 50014:Token 過時了;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
MessageBox.confirm('你已被登出,能夠取消繼續留在該頁面,或者從新登陸', '肯定登出', {
confirmButtonText: '從新登陸',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('FedLogOut').then(() => {
location.reload() // 爲了從新實例化vue-router對象 避免bug
})
})
}
return null
} else {
return response.data
}
},
error => {
if (error.message === 'Network Error' && error.config.url.endsWith('/license')) {
Message({
message: '沒法鏈接到本地代理程序,請確認代理程序是否運行正常!',
type: 'error',
duration: 5 * 1000
})
} else {
console.log(error + ' ' + error.config.url) // for debug
Message({
message: error.message + ' ' + error.config.url,
type: 'error',
duration: 5 * 1000
})
}
return Promise.reject(error)
}
)
export default service
 (2)springBoot

  

package xin.toheart.door.filter; import org.slf4j.Logger;import org.slf4j.LoggerFactory; import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Arrays;import java.util.HashSet;import java.util.Set; @WebFilter(urlPatterns = { "/*" }, filterName = "loginAuthFilter")public class LoginAuthFilter implements Filter { private static Logger logger = LoggerFactory.getLogger(LoginAuthFilter.class); @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse rep = (HttpServletResponse) response; // 設置容許多個域名請求 String[] allowDomains = {"http://www.toheart.xin","http://192.168.10.213:8080","http://localhost:8080"}; Set allowOrigins = new HashSet(Arrays.asList(allowDomains)); String originHeads = req.getHeader("Origin"); if(allowOrigins.contains(originHeads)){ //設置容許跨域的配置 // 這裏填寫你容許進行跨域的主機ip(正式上線時能夠動態配置具體容許的域名和IP) rep.setHeader("Access-Control-Allow-Origin", originHeads); } // 設置服務器容許瀏覽器發送請求都攜帶cookie rep.setHeader("Access-Control-Allow-Credentials","true"); // 容許的訪問方法 rep.setHeader("Access-Control-Allow-Methods","POST, GET, PUT, OPTIONS, DELETE, PATCH"); // Access-Control-Max-Age 用於 CORS 相關配置的緩存 rep.setHeader("Access-Control-Max-Age", "3600"); rep.setHeader("Access-Control-Allow-Headers","token,Origin, X-Requested-With, Content-Type, Accept,mid,X-Token"); response.setCharacterEncoding("UTF-8");// response.setContentType("application/json; charset=utf-8"); chain.doFilter(request, response); } @Override public void init(FilterConfig arg0) throws ServletException { } }

相關文章
相關標籤/搜索