每当我们拥有一项新功能时,我们都想添加到现有应用程序中,作为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': [...]})