Lekérdezés alapú webalkalmazás korlátozásainak elemzése
Az alkalmazás jelenlegi architektúrája úgy jelenti a készletadatokat, hogy lekéri az összes részvényáradatot a kiszolgálóról egy időzítő alapján. Ezt a kialakítást általában lekérdezéses alapúnak hívjuk.
Kiszolgáló
A tőzsdei árfolyamadatok egy Azure Cosmos DB-adatbázisban vannak tárolva. HA EGY HTTP-kérés aktiválja, a függvény getStocks
az adatbázis összes sorát visszaadja.
import { app, input } from "@azure/functions";
const cosmosInput = input.cosmosDB({
databaseName: 'stocksdb',
containerName: 'stocks',
connection: 'COSMOSDB_CONNECTION_STRING',
sqlQuery: 'SELECT * from c',
});
app.http('getStocks', {
methods: ['GET'],
authLevel: 'anonymous',
extraInputs: [cosmosInput],
handler: (request, context) => {
const stocks = context.extraInputs.get(cosmosInput);
return {
jsonBody: stocks,
};
},
});
- Adatok lekérése: A kód első szakasza, a CosmosInput lekéri a
stocks
tábla összes elemét a lekérdezésselSELECT * from c
együtt astocksdb
Cosmos DB adatbázisában. - Adatok visszaadása: A kód második szakasza, az app.http bemenetként fogadja ezeket az adatokat a függvénybe
context.extraInputs
, majd válasz törzsként adja vissza az ügyfélnek.
Ügyfél
A mintaügyfél Vue.js használ a felhasználói felület és a Beolvasás ügyfél megírásához az API-nak küldött kérések kezeléséhez.
A HTML-oldal időzítővel öt másodpercenként küld kérést a kiszolgálónak a készletek lekéréséhez. A válaszban egy tömböt kapunk a tőzsdei adatokkal, és ezt jelenítjük meg a felhasználónak.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css" integrity="sha256-8B1OaG0zT7uYA572S2xOxWACq9NXYPQ+U5kHPV1bJN4=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<title>Stocks | Enable automatic updates in a web application using Azure Functions and SignalR</title>
</head>
<body>
<!-- BEGIN: Replace markup in this section -->
<div id="app" class="container">
<h1 class="title">Stocks</h1>
<div id="stocks">
<div v-for="stock in stocks" class="stock">
<div class="lead">{{ stock.symbol }}: ${{ stock.price }}</div>
<div class="change">Change:
<span :class="{ 'is-up': stock.changeDirection === '+', 'is-down': stock.changeDirection === '-' }">
{{ stock.changeDirection }}{{ stock.change }}
</span></div>
</div>
</div>
</div>
<!-- END -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js" integrity="sha256-chlNFSVx3TdcQ2Xlw7SvnbLAavAQLO0Y/LBiWX04viY=" crossorigin="anonymous"></script>
<script src="bundle.js" type="text/javascript"></script>
</body>
</html>
import './style.css';
function getApiUrl() {
const backend = process.env.BACKEND_URL;
const url = (backend) ? `${backend}` : ``;
return url;
}
const app = new Vue({
el: '#app',
interval: null,
data() {
return {
stocks: []
}
},
methods: {
async update() {
try {
const url = `${getApiUrl()}/api/getStocks`;
console.log('Fetching stocks from ', url);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
app.stocks = await response.json();
} catch (ex) {
console.error(ex);
}
},
startPoll() {
this.interval = setInterval(this.update, 5000);
}
},
created() {
this.update();
this.startPoll();
}
});
startPoll
A metódus lekérdezésének megkezdése után a update
metódust öt másodpercenként hívjuk meg. A metóduson update
belül a rendszer get kérést küld az /api/getStocks
API-végpontnak, és az eredmény a app.stocks
felhasználói felületet frissíti.
A kiszolgáló és az ügyfélkód viszonylag egyszerű: az összes adat lekérése, az összes adat megjelenítése. Amint az elemzésünkből kiderül, ez az egyszerűség bizonyos korlátozásokat is magában hordoz.
Prototípus-megoldás elemzése
A Tailwind Traders mérnökeként azonosította ennek az időzítőalapú lekérdezési módszernek néhány hátrányait.
Szükségtelen API-kérések: Az időzítőalapú lekérdezési prototípusban az ügyfélalkalmazás kapcsolatba lép a kiszolgálóval, hogy vannak-e módosítások a mögöttes adatokon.
Szükségtelen oldalfrissítések: Miután a kiszolgálóról visszaadta az adatokat, a teljes készletlista frissül a weblapon, még akkor is, ha az adatok nem változtak. Ez a lekérdezéses megoldás tehát nem hatékony.
Lekérdezési időközök: A forgatókönyv legjobb lekérdezési időközének kiválasztása szintén kihívást jelent. A lekérdezésnél mindenképpen figyelembe kell vennünk, hogy milyen költségekkel járnak a háttérrendszerhez irányuló hívások, és el kell döntenünk, hogy milyen gyakran szeretnénk, hogy az alkalmazást új adatokra reagáljon. Az új adatok elérhetővé válása és az alkalmazás észlelése között gyakran előfordulnak késések. Az alábbi ábra ezt a problémát illusztrálja.
Legrosszabb esetben az új adatok észlelésének késése megegyezik a lekérdezési időközzel. Érdemesebb tehát kisebb időközt használni?
Adatmennyiség: Az alkalmazás méretezése során az ügyfél és a kiszolgáló között kicserélt adatok mennyisége problémába ütközik. Minden egyes HTTP-kérelem fejléce több száz bájtnyi adatot tartalmaz, és ehhez hozzáadódik még a munkamenet cookie-ja is. Ezek mind jelentős terhelést és elpazarolt erőforrásokat jelentenek, különösen nagy forgalom mellett, és fölöslegesen veszik igénybe a kiszolgálót.
Most, hogy jobban ismeri a prototípust, ideje, hogy az alkalmazás futtassa a gépén.
A CORS támogatása
A Functions-alkalmazás local.settings.json fájljában a szakasz az Host
alábbi beállításokat tartalmazza.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "<STORAGE_CONNECTION_STRING>",
"FUNCTIONS_WORKER_RUNTIME": "node",
"AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
"COSMOSDB_CONNECTION_STRING": "<COSMOSDB_CONNECTION_STRING>"
},
"Host" : {
"LocalHttpPort": 7071,
"CORS": "http://localhost:3000",
"CORSCredentials": true
}
}
Ez a konfiguráció lehetővé teszi, hogy a localhost:3000 címen futó webalkalmazás kéréseket küldjön a localhost:7071 címen futó függvényalkalmazásnak. A tulajdonság CORSCredentials
arra utasítja a függvényalkalmazást, hogy fogadja el a kérelemben szereplő hitelesítő cookie-kat.
Az eltérő eredetű erőforrások megosztása (CORS) egy olyan HTTP-szolgáltatás, amely egy adott tartományban futó webalkalmazás számára teszi lehetővé, hogy hozzáférjen egy másik tartomány erőforrásaihoz. A webböngészők azonoseredet-szabálynak nevezett biztonsági korlátozással akadályozzák meg, hogy egy adott weblap más tartományokból hívjon meg API-kat. A CORS biztonságos megoldást nyújt arra, hogy a forrástartományból más tartományokban lévő API-k legyenek meghívhatók.
Helyi futtatáskor a CORS a minta local.settings.json fájljában van konfigurálva, amely soha nem lesz közzétéve. Az ügyfélalkalmazás (7. egység) telepítésekor frissítenie kell a CORS-beállításokat is a függvényalkalmazásban, hogy engedélyezze az ügyfélalkalmazásból való hozzáférést.