如何處理舊移動應用程序版本的後端更改

每當我們擁有一項新功能時,我們都想添加到現有應用程序中,作為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': [...]})