Analysera begränsningarna för en avsökningsbaserad webbapp
Programmets aktuella arkitektur rapporterar aktieinformation genom att hämta all aktiekursinformation från servern baserat på en timer. Den här designen kallas ofta för avsökningsbaserad design.
Server
Aktiekursinformationen lagras i en Azure Cosmos DB-databas. När den utlöses av en HTTP-begäran returnerar funktionen getStocks
alla rader från databasen.
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,
};
},
});
- Hämta data: Det första avsnittet av kod, cosmosInput, hämtar alla objekt i
stocks
tabellen, med fråganSELECT * from c
, istocksdb
databasen i Cosmos DB. - Returnera data: Det andra kodavsnittet, app.http, tar emot dessa data i funktionen som indata i
context.extraInputs
och returnerar dem sedan som svarstext tillbaka till klienten.
Klient
Exempelklienten använder Vue.js för att skapa användargränssnittet och Fetch-klienten för att hantera begäranden till API:et.
HTML-sidan använder en timer för att skicka en begäran till servern var femte sekund för att begära lager. Svaret returnerar en matris med aktier, som sedan visas för användaren.
<!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
När metoden börjar avsöka update
anropas metoden var femte sekund. update
I metoden skickas en GET-begäran till API-slutpunkten /api/getStocks
och resultatet är inställt på app.stocks
, vilket uppdaterar användargränssnittet.
Server- och klientkoden är relativt enkel: hämta alla data, visa alla data. Som vi får reda på i vår analys medför den här enkelheten vissa begränsningar.
Analys av prototyplösning
Som Tailwind Traders-tekniker har du identifierat några av nackdelarna med den här tidsbaserade avsökningsmetoden.
Onödiga API-begäranden: I den tidsbaserade avsökningsprototypen kontaktar klientprogrammet servern oavsett om det finns ändringar i underliggande data eller inte.
Onödiga siduppdateringar: När data returneras från servern uppdateras hela listan med aktier på webbsidan, även om inga data har ändrats. Den här avsökningsmekanismen är en ineffektiv lösning.
Avsökningsintervall: Att välja det bästa avsökningsintervallet för ditt scenario är också en utmaning. Avsökning tvingar dig att välja mellan hur mycket varje anrop till serverdelen kostar och hur snabbt du vill att appen svarar på nya data. Fördröjningar finns ofta mellan den tid då nya data blir tillgängliga och den tid då appen identifierar dem. Problemet visas i följande bild.
I värsta fall är den potentiella fördröjningen vid identifiering av nya data lika med sökningsintervallet. Varför då inte använda ett mindre intervall?
Mängd data: När programmet skalas blir mängden data som utbyts mellan klienten och servern ett problem. Varje HTTP-frågehuvud innehåller hundratals byte med data tillsammans med sessionens cookie. All denna belastning, särskilt tung, leder till slösade resurser och anstränger servern i onödan.
Nu när du är mer bekant med prototypen är det dags att köra programmet på datorn.
Stöd för CORS
I den local.settings.json filen i Functions-appen Host
innehåller avsnittet följande inställningar.
{
"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
}
}
Med den här konfigurationen kan ett webbprogram som körs på localhost:3000 göra begäranden till funktionsappen som körs på localhost:7071. Egenskapen CORSCredentials
instruerar funktionsappen att acceptera cookies för autentiseringsuppgifter från begäran.
CORS (Cross-origin resource sharing) är en HTTP-funktion som gör det möjligt för ett webbprogram som körs i en domän att komma åt resurser i en annan domän. Webbläsare implementerar en säkerhetsbegränsning som har samma ursprungsprincip som förhindrar att en webbsida anropar API:er i en annan domän. CORS är ett säkert sätt att tillåta en domän (ursprungsdomänen) att anropa API:er i en annan domän.
När du kör lokalt konfigureras CORS åt dig i exemplets local.settings.json-fil, som aldrig publiceras. När du distribuerar klientappen (enhet 7) måste du även uppdatera CORS-inställningarna i funktionsappen för att tillåta åtkomst från klientappen.