1. 程式人生 > >Django+Vue+微信登入授權前後端分離實現過程中踩坑問題階段性總結

Django+Vue+微信登入授權前後端分離實現過程中踩坑問題階段性總結

我要說明的是另外以下幾點:

  1. 跨域問題
    關於跨域問題是指在開發前端頁面使用前端熱更新除錯過程中與Django進行的資料請求產生的跨域問題.
    例如你在本地
    http://localhost:8080/#/
    除錯介面請求Django本地伺服器
    http://localhost:8000/
    下的Api資料時就會產生跨域問題,因為埠號不一致.
    解決跨域問題需要前端後端同時解決.
    前端:
    a. 在config目錄下的index.js中dev下找到proxyTable
    proxyTable
    修改為如圖程式碼如下

    '/apis': {//此處/apis並不需要保持一致.
                // 測試環境
                target: 'http://localhost:8000',  // 介面域名
                changeOrigin: true,  //是否跨域
                pathRewrite: {
                    '^/apis': ''   //需要rewrite重寫的,
                }
            }
    

    b.修改config/dev.env.js檔案新增

    API_ROOT: '"/apis"'
    

    在這裡插入圖片描述
    修改config/prod.env.js

    API_ROOT: '"你自己的生產釋出地址"'
    

    c.你原始請求Django資料的url
    http://localhost:8000/api/testApi
    修改為
    process.env.API_ROOT + ‘/api/testApi’
    當然你也可以直接設定axios的baseURL為process.env.API_ROOT
    後端:
    Django可以使用第三方包 django-cors-headers 來解決跨域問題,具體操作如下:
    a. cd 到Django專案資料夾
    b. 執行 python pip install django-cors-headers

    安裝django-cors-headers
    c. settings.py 新增加星號那一行,注意中介軟體載入順序,列表是有序的。

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        **'corsheaders.middleware.CorsMiddleware',**
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    

    在下面再新增

    CORS_ORIGIN_ALLOW_ALL = True
    
  2. 前後端專案目錄結構問題
    在Django中以及在Vue中都有各自的靜態檔案存放路徑,假如我們上生產的時候想把所有靜態檔案都放在一起以方便靜態檔案的轉發與搜尋的話,例如可以放在Django的statics靜態資料夾中.
    需要修改我們build出來的
    在這裡插入圖片描述
    修改之後再build你會發現
    目錄結構的變化
    在這裡插入圖片描述
    那麼我們在setting.py中靜態檔案搜尋路徑中的前端路徑就不需要了在這裡插入圖片描述

  3. 進入頁面需要微信登入授權問題
    如果我們要開發微信公眾號等微信相關頁面時,進入前端頁面需要微信授權的情況下,可以使用在這裡插入圖片描述
    其實一開始我遇到了一個問題:進入介面的時候沒有使用裝飾器,在請求Api的時候對Api使用了裝飾器,當第一次請求授權成功之後因為裝飾器中跳轉連結是使用redirect_url = request.get_raw_uri()獲取當前訪問的連結進行跳轉所以授權成功之後不是進入到訪問頁面而是會顯示Api成功的response應答資料.當我收到301進行字串擷取替換的過程中,發現授權頁面一直在不停的迴圈跳轉.不知道什麼原因???

  4. axios封裝問題

    import axios from 'axios'
    
    // axios預設公共引數
    const http = axios.create({
    	baseURL: process.env.API_ROOT,
    	timeout: 10000,
    	withCredentials: true, // 跨域
    	headers: {
    		'X-Requested-With': 'XMLHttpRequest',
    		'Cache-Control': 'no-cache',
    	},
    });
    
    let cancel, promiseArr = {}
    const CancelToken = axios.CancelToken;
    //請求攔截器
    http.interceptors.request.use(config => {
    	//發起請求時,取消掉當前正在進行的相同請求
    	if (promiseArr[config.url]) {
    		promiseArr[config.url]('操作取消')
    		promiseArr[config.url] = cancel
    	} else {
    		promiseArr[config.url] = cancel
    	}
    	return config
    }, error => {
    	return Promise.reject(error)
    })
    
    http.interceptors.response.use(response => {
    		let {
    			status,
    			statusText,
    			data
    		} = response;
    		if (err_check(status, statusText, data) && data) {
    			return Promise.resolve(data);
    		} else {
    			return Promise.reject(data);
    		}
    	},
    	err => {
    		if (axios.isCancel(err)) {
    			err.response = {
    				status:100,
    				statusText:err.message
    			}
    		}
    		else if (err && err.response) {
    			switch (err.response.status) {
    				case 400:
    					err.message = '錯誤請求';
    					break;
    				case 401:
    					err.message = '未授權,請重新登入';
    					break;
    				case 403:
    					err.message = '拒絕訪問';
    					break;
    				case 404:
    					err.message = '請求錯誤,未找到該資源';
    					break;
    				case 405:
    					err.message = '請求方法未允許';
    					break;
    				case 408:
    					err.message = '請求超時';
    					break;
    				case 500:
    					err.message = '伺服器端出錯';
    					break;
    				case 501:
    					err.message = '網路未實現';
    					break;
    				case 502:
    					err.message = '網路錯誤';
    					break;
    				case 503:
    					err.message = '服務不可用';
    					break;
    				case 504:
    					err.message = '網路超時';
    					break;
    				case 505:
    					err.message = 'http版本不支援該請求';
    					break;
    				default:
    					err.message = `連線錯誤${err.response.status}`;
    			}
    		} else {
    			err.message = "連線到伺服器失敗";
    		}
    		console.log('err.message:',err.message);
    		return Promise.reject(err.response)
    	})
    
    const err_check = (code, message, data) => {
    	if (code == 200) {
    		return true
    	}
    	return false
    }
    
    export default {
    	httpRequest(method, url, param) {
    		return new Promise((resolve, reject) => {
    			http({
    				method,
    				url,
    				data: param,
    				cancelToken: new CancelToken(c => {
    					cancel = c
    				})
    			})
    			.then(res => {
    				resolve(res)
    			})
    			.catch(err => {
    				reject(err)
    			})
    		})
    	},
    	cancelRequest(msg){
    			// 第一次執行cancelRequest()時可能還未傳送請求,會報錯,新增如下判斷
    	  if (typeof cancel === 'function') {
    	    // 取消請求
    	    cancel(msg)
    	  }
    	}
    }
    
    
  5. axios使用post請求後端無法獲取資料問題
    安裝qs,在 main.js裡引入

    import qs from 'qs';
    Vue.prototype.$qs = qs;
    

    在vue元件裡面請求方法

    let postData = this.$qs.stringify({
        key1:value1,
        key2:value2,
    });
    this.$axios({
        method: 'post',
        url:'url',
        data:postData
    }).then((res)=>{
        
    });
    
  6. axios取消重複請求

    let cancel, promiseArr = {}
    const CancelToken = axios.CancelToken;
    //請求攔截器
    http.interceptors.request.use(config => {
    	//發起請求時,取消掉當前正在進行的相同請求
    	if (promiseArr[config.url]) {
    		promiseArr[config.url]('操作取消')
    		promiseArr[config.url] = cancel
    	} else {
    		promiseArr[config.url] = cancel
    	}
    	return config
    }, error => {
    	return Promise.reject(error)
    })
    
  7. 引入外部JS樣式問題例如微信樣式weui
    a.安裝 weui, 並在 main.js 中匯入weui.min.css

    npm install --save weui // 安裝weui
    
    import 'weui/dist/style/weui.min.css' // 在main.js中匯入weui.min.css
    

    b.在我們專案的vue檔案中 引入 weui 的UI佈局

    <template>
    	<div class="weui-cells " id="cards">
    	    <div class="weui-cell" id="cardInfo" style="border-bottom:1px solid #e5e5e5 !important;">
    	        <div class="weui-cell__hd " id="card_detail">
    	            我的卡片;
    	        </div>
    	        <div class="weui-cell__bd">
    		<span id="myCardCounts">{{cardInfoList.length}}</span> 張
    	        </div>
    	        <div class="weui-cell__ft" ><button class="weui-btn weui-btn_mini weui-btn_default" @click="addCard">新增
    	            </button></div>
    	    </div>
    	</div>
    </template>
    
  8. background-image圖片路徑問題
    參考vue踩坑系列——backgroundImage路徑問題
    但是我發現我放到Django中statics下的圖片依然可以訪問成功

    // cardInfo.cardImage為Django目錄下的路徑:/statics/image/common/cards/card-sptcc.png
    backgroundImage: 'url(' + cardInfo.cardImage + ')'
    
  9. axios返回快取問題(from disk cache)
    axios請求頭中新增’Cache-Control’: ‘no-cache’,

    headers: {
    		'X-Requested-With': 'XMLHttpRequest',
    		'Cache-Control': 'no-cache',
    	},
    
  10. Django經過微信授權後帶各種引數的url第一次路由到Vue時,Vue路由直接直接拼接path問題.
    例如:Django下url.py中

    url('frontend', wx_login_required(TemplateView.as_view(template_name="index.html"))),
    

    Vue下router中

    {
          name: 'login',
          path: '/login',
          component: Login
     }
    

    可能你想要得到的連結是這樣的

    http://ip:port/frontend/login?appId=你的
    

    但是當你按照這樣的地址輸入時卻不顯示任何元件內容.你就很奇怪了,於是經過redirect你發現經過Django裝飾器的微信授權之後實際地址確實這樣的.

    http://ip:port/frontend/login?appId=你的&code=&state=STATE#/login
    

    問題描述:由於vue使用vue-router時,路徑中會有#的欄位導致的.在位址列中不存在#所以路由會不識別改地址,重定向的時候會直接在後面新增#/地址.
    目前解決方案的思路
    1.前端去除# : 使用router的history模式, 且在伺服器端進行配置
    參考:問題11
    2.使用JSSDK進行前端授權
    參考Vue:在Vue中實現微信網頁授權和分享