每當我們擁有一項新功能時,我們都想添加到現有應用程序中,作為Web開發人員,我們都將同時更新前端和後端。然後,我們將更改部署到生產環境中,並將其稱為一天。
但是,在移動應用程序的情況下,同一概念並不總是適用。因為並非每個人都會自動更新該應用程序。因此,在移動應用程序的較舊版本中,對後端代碼的新更改可能無法正常工作。這是新版本後的大多數用戶。
假設我們有一個應用程序,可以讓用戶跟踪他們的每月費用。我們有一個React Native應用程序,可以從用戶那裡獲取輸入和將費用存儲在數據庫中的後端。以下是我們用來與後端通信的JSON格式:
1{
2 data: [
3 {
4 "id": 1,
5 "amount": 100,
6 "date": "2021-01-01",
7 "category": "Food",
8 "subcategory": "Groceries",
9 "description": "Bought groceries for the month",
10 },
11 {
12 "id": 2,
13 "amount": 200,
14 "date": "2021-01-02",
15 "category": "Transportation",
16 "subcategory": "Gas",
17 "description": "Filled up the gas tank",
18 }
19 ]
20}
假設我們有一個正在消耗API的React Native應用程序,則我們正在顯示列表中的費用。像這樣:
1<View>
2 {result?.data?.map((expense) => (
3 <View>
4 <Text>{expense.amount}</Text>
5 <Text>{expense.date}</Text>
6 <Text>{expense.category}</Text>
7 <Text>{expense.subcategory}</Text>
8 <Text>{expense.description}</Text>
9 </View>
10 ))}
11</View>
但是,如果我們現在想添加一個使用戶還可以存儲其收入的功能怎麼辦?為了實現這一目標,我們需要更新後端代碼,以便將收入存儲在數據庫中。在檢索數據時,我們需要以以下JSON格式將數據寄回:
1{
2 data: {
3 expenses: [
4 {
5 "id": 1,
6 "amount": 100,
7 "date": "2021-01-01",
8 "category": "Food",
9 "subcategory": "Groceries",
10 "description": "Bought groceries for the month",
11 },
12 {
13 "id": 2,
14 "amount": 200,
15 "date": "2021-01-02",
16 "category": "Transportation",
17 "subcategory": "Gas",
18 "description": "Filled up the gas tank",
19 }
20 ],
21 incomes: [
22 {
23 "id": 1,
24 "amount": 10000,
25 "date": "2021-01-01",
26 "category": "Salary",
27 "subcategory": "Full-time",
28 "description": "Received salary for the month",
29 },
30 {
31 "id": 2,
32 "amount": 2050,
33 "date": "2021-01-02",
34 "category": "Freelance",
35 "subcategory": "Writing",
36 "description": "Received freelance payment for the month",
37 }
38 ]
39 }
40}
因此,移動應用程序將必須更新代碼以處理新的JSON格式。
1<View>
2- {result?.data?.map((expense) => (
3+ {result?.data?.expenses?.map((expense) => (
4 <View>
5 <Text>{expense.amount}</Text>
6 <Text>{expense.date}</Text>
7 <Text>{expense.category}</Text>
8 <Text>{expense.subcategory}</Text>
9 <Text>{expense.description}</Text>
10 </View>
11 ))}
12</View>
但是在移動應用程序的較舊版本中,代碼仍將使用舊的JSON格式。因此該應用將崩潰。將數據保存到後端時也適用。移動應用程序的較舊版本將無法以新的JSON格式保存數據,以防我們有一個驗證器,該驗證器在將JSON格式保存到數據庫之前檢查了JSON格式。但是在這裡,我們只會談論響應格式。我們確定,一旦您知道技巧,您就可以自行處理“有條件保存到數據庫”部分。
為了解決此問題,我們可以有條件地為移動應用程序的舊版本返回舊的JSON格式。並返回新版本的移動應用程序的新JSON格式。但是,後端服務器將如何知道用戶使用哪個版本的移動應用程序?那就是庫稱為“ React-Native-Device-Info”的庫。使用此庫可以使用移動應用程序的版本,並使用自定義標題“ MobileAppersion”將其發送到後端服務器。在後端,我們可以檢查標題“ mobileAppversion”是否存在,並且大於或等於我們要支持的移動應用程序的版本。如果是這樣,我們可以返回新的JSON格式,否則我們可以返回舊的JSON格式。
如果您使用的是Apisauce(建議使用),則可以設置這樣的標題:
1import DeviceInfo from "react-native-device-info"
2
3...
4setAllHeaders(value?: string, appVersion?: string) {
5 api.apisauce.setHeader("Authorization", `Bearer ${value}`)
6 api.apisauce.setHeader("MobileAppVersion", appVersion || "")
7}
8...
9
10setAllHeaders(token, DeviceInfo.getVersion())
或者,如果您不使用Apisauce,則可以手動設置標題:
1async function getData(url: string, appVersion: string) {
2 const response = await fetch(url, {
3 headers: {
4 'Authorization': 'Bearer Token',
5 'MobileAppVersion': appVersion || ""
6 }
7 })
8 const data = await response.json()
9 return data
10}
11
12...
13// get the data from the api (e.g. inside useEffect, or a button press)
14const result = await getData("https://api.example.com", DeviceInfo.getVersion())
15...
然後,在後端代碼中,您可以根據應用程序版本有條件地返迴響應。
1const express = require('express')
2const app = express()
3
4app.get('/', (req, res) => {
5 const appVersion = req.headers['MobileAppVersion']
6 if (appVersion && appVersion >= '2.0.0') { // if the app version is 2.0.0 or higher
7 res.json({ data: { expenses: [...], incomes: [...]} })
8 }
9 else {
10 // if the app version is lower than 2.0.0, older response format
11 res.json({ data: [] })
12 }
13})
或者,如果您與Django一起使用Python,則可以做類似的事情:
1from django.http import JsonResponse
2
3class get_data(request):
4 def get(self, request):
5 app_version = request.headers.get('MobileAppVersion', '1.0.0')
6 if app_version and app_version >= '2.0.0':
7 # if the app version is 2.0.0 or higher
8 return JsonResponse({'data': {expenses: [...], incomes: [...]}})
9 else:
10 # if the app version is lower than 2.0.0, older response format
11 return JsonResponse({'data': [...]})