I det här inlägget visar vi dig hur du bygger en webbadressförkortningstjänst som bit.ly eller goo.gl med Express.js (Node.js) och MongoDB. Här är en demo av den slutliga produkten vi kommer att bygga genom vår MongoDB-värdplattform.
Hur fungerar en URL Shortener?
På en mycket hög nivå fungerar URL-förkortaren genom att ta en inmatad URL och skapa en relativt förkortad version förenklad till ett format som är lätt att dela. Den förkortade hashen kommer att genereras genom att baskoda en automatiskt inkrementerad räknare och skapar en hash på minst tre tecken som ökar när antalet lagrade webbadresser ökar.
När den förkortade versionen av URL:en besöks kommer tjänsten att avkoda hashen för att hämta den ursprungliga URL:en lagrad i MongoDB och sedan omdirigera din användare till den.
Komma igång
Här är en lista över de tekniker vi kommer att använda för att bygga URL-förkortaren i denna handledning:
-
Express.js (Node.js backend)
Ett ramverk för webbapplikationer för Node.js. Vi kommer att använda det för att bygga ett API för att förkorta webbadresser och omdirigera användare till den ursprungliga webbadressen.
-
MongoDB (lagring av webbadresser)
En NoSQL-databas perfekt för den här applikationen. Det ger en flexibel schemadesign och är lätt att komma igång med. I den här handledningen kommer vi att använda ett delat MongoDB-kluster på ScaleGrid. Det tar mindre än 5 minuter att konfigurera, och du kan skapa en kostnadsfri 30-dagars provperiod här för att komma igång.
-
HTML, CSS, JavaScript (front-end)
HTML, CSS och JavaScript kommer att användas för att bygga applikationens gränssnitt som dina användare kommer att använda för att förkorta webbadresser.
URL Shortener Tutorial
-
Konfigurera MongoDB-databasstrukturen
Låt oss börja med att skapa ett delat MongoDB-kluster på ScaleGrid. Detta är det enklaste sättet att skapa ett snabbt kluster, men du kan också installera MongoDB på din dator och komma igång där.
När klustret har skapats kommer du att få en anslutningssträng som kan kopieras med ett enda klick från sidan med klusterdetaljer. Vi behöver den här strängen för att ansluta till klustret från vår applikation. Kom ihåg att aldrig dela din anslutningssträng med någon.
Vi behöver två samlingar för URL-förkortaren:
-
Samling 1
En samling för att lagra webbadressen och dynamiskt genererat ID:
-
Samling 2
En samling för att upprätthålla räknaren som automatiskt inkrementeras när en ny URL lagras i den tidigare samlingen. Ett nytt dokument skapas i den tidigare samlingen med denna nyligen inkrementerade räknare:
Det är viktigt att notera att vi inte lagrar hasharna någonstans i databasen. Hashen kommer att baskodas och avkodas dynamiskt med den allmänna algoritmen som kommer att resultera i det unika ID:t som lagras i den första samlingen. Detta ID kommer sedan att hämta oss den ursprungliga webbadressen som användaren kommer att omdirigera till.
För den här handledningen kommer vi att använda den vanliga base64-kodnings- och avkodningsmekanismen för att generera vår unika förkortade hash. För mer information om kodning/avkodning av strängar med base64, se följande MDN Web Doc.
-
-
Konfigurera Express.js Backend
Här är en lista över beroenden som krävs för att ställa in vår Node.js-backend:
- express (basapp)
- body-parser (tillägg för att analysera data som skickas över HTTP-förfrågningar)
- btoa (base64-kodning)
- atob (base64-avkodning)
- dotenv (lagring av anslutningssträng i en .env-fil för utvecklingsändamål)
- mongoose (adapter för MongoDB på Node.js)
Här är en exempelversion av package.json som du kan använda för att konfigurera appen:
{ "name":"sg-url-shortener", "version":"1.0.0", "description":"En enkel URL-förkortare byggd med Node.js och MongoDB", "dependencies":{ " atob":"^2.0.3", "body-parser":"^1.15.2", "btoa":"^1.1.2", "dotenv":"^4.0.0", "express":" ^4.10.2", "mongoose":"^4.13.7" }, "main":"index.js", "scripts":{ "start":"node index.js" }, "engines":{ "node":"4.8.4" }}
Kör “npm install” för att installera alla nödvändiga beroenden.
När alla våra beroenden har ställts in måste vi ansluta till vårt delade MongoDB-kluster. Skapa en .env-fil i projektets rot och lägg till anslutningssträngen till den. Du kan hämta anslutningssträngen från din klusterinformationssida under fliken Översikt på ScaleGrid-konsolen.
connectionString=mongodb://user:password@devservers
Innan vi börjar skriva kod är det bra att visualisera appflödet så att vi har en god förståelse för hur förkortningsprocessen kommer att fungera. Här är ett diagram som visar processen för URL-förkortning:
Här är ett diagram som visar processen för omdirigering när en förkortad webbadress besöks:
Nu när vi har visualiserat hela processen är det dags att översätta ovanstående flödesscheman till kod.
-
Initiera programmet
Innan vi börjar skriva affärslogik måste vi initiera vår applikation med våra nodmoduler och ställa in en server.
Ladda .env-filer endast i utvecklarläge. Eftersom demoapplikationen finns på Heroku har en miljövariabel skapats från Heroku-instrumentpanelen som redan innehåller anslutningssträngen där:
if(process.env.NODE_ENV !=='produktion') { require('dotenv').load();}
Initiering av program, server- och mellanprograminstallation. Observera att vi också får anslutningssträngen från miljövariabeln:
var express =require('express'), bodyParser =require('body-parser'), app =express(), http =require('http').Server(app), mongoose =require('mongoose '), btoa =require('btoa'), atob =require('atob'), lova, connectionString =process.env.connectionString, port =process.env.PORT || 8080;http.listen(port, function() { console.log('Server startade. Lyssnar på *:' + port);});app.use(express.static('public'));app.use( bodyParser.urlencoded({ extended:true}));
Basväg för att ladda upp fronten av vår app:
app.get('/', function(req, res) { res.sendFile('views/index.html', { root:__dirname });});
-
Lagra webbadresser i MongoDB
Låt oss börja med att skapa insamlingsscheman för att lagra data. Som diskuterats ovan behöver vi två samlingar:en för att lagra den automatiskt inkrementerade räknaren och den andra för att lagra webbadresserna.
var countersSchema =new mongoose.Schema({ _id:{ type:String, required:true }, count:{ type:Number, default:0 }});var Counter =mongoose.model('Counter', countersSchema );var urlSchema =new mongoose.Schema({ _id:{type:Number}, url:'', created_at:''});urlSchema.pre('save', function(next) { console.log('running pre-save'); var doc =this; Counter.findByIdAndUpdate({ _id:'url_count' }, { $inc:{ count:1 } }, function(err, counter) { if(err) return next(err); console.log(counter); console.log(counter.count); doc._id =counter.count; doc.created_at =new Date(); console.log(doc); next(); });});var URL =mongoose.model('URL', urlSchema);
Koden ovan skapar de två samlingarna och ställer in vår databas för att lagra dessa samlingar. Vi använder också en pre-save hook för URL-schemat eftersom vi behöver automatiskt öka räknaren och logga datum och tid då webbadressen skapades.
Närnäst måste vi se till att vi startar vår applikation på nytt och att alla tidigare poster raderas. När vi har återställt, initierar vi vår räknare med ett startvärde på 10 000 för att ställa in URL-förkortningsprocessen. Du kan börja med vilket värde som helst. Detta valdes slumpmässigt och kommer automatiskt att öka med ett värde på ett.
promise =mongoose.connect(connectionString, { useMongoClient:true});promise.then(function(db) { console.log('ansluten!'); URL.remove({}, function() { console. log('URL-samling borttagen'); }) Counter.remove({}, function() { console.log('Räknarsamling borttagen'); var counter =new Counter({_id:'url_count', count:10000} ); counter.save(function(err) { if(err) return console.error(err); console.log('counter inserted'); }); });});
Vår applikation är nu redo att börja acceptera och förkorta webbadresser! Låt oss skapa ett POST API som vårt gränssnitt kommer att använda för att skicka webbadressen:
app.post('/shorten', function(req, res, next) { console.log(req.body.url); var urlData =req.body.url; URL.findOne({url:urlData} , function(err, doc) { if(doc) { console.log('entry found in db'); res.send({ url:urlData, hash:btoa(doc._id), status:200, statusTxt:' OK' }); } else { console.log('entry NOT found in db, Saving new'); var url =new URL({ url:urlData }); url.save(function(err) { if(err) return console.error(err); res.send({ url:urlData, hash:btoa(url._id), status:200, statusTxt:'OK' }); }); } });});
Som beskrivs i flödesdiagrammet kontrollerar vi att den finns i databasen när en giltig webbadress har tagits emot.
Om den hittas avkodar vi motsvarande _id-fält och returnerar hashen. Vårt gränssnitt konstruerar den förkortade URL:en och presenterar den för användaren för omdirigering.
Om ingen URL hittas sparar vi ett nytt dokument i samlingen. Kom ihåg att ett försparasteg körs varje gång URL:en sparas. Detta kommer att automatiskt öka räknaren och logga aktuellt datum och tid. Efter att dokumentet har lagts till skickar vi hashen till vårt gränssnitt som konstruerar den förkortade URL:en och presenterar den för användaren för omdirigering.
-
Omdirigera användare
Vi är nästan klara! När våra förkortade webbadresser har skapats behöver vi ett sätt att omdirigera användaren när en förkortad webbadress besöks.
app.get('/:hash', function(req, res) { var baseid =req.params.hash; var id =atob(baseid); URL.findOne({ _id:id }, function(err , doc) { if(doc) { res.redirect(doc.url); } else { res.redirect('/'); } });});
Koden ovan letar efter en hash i den förkortade URL:en, base64 avkodar den, kontrollerar om detta ID finns i samlingen och omdirigerar användaren därefter. Om inget ID hittas omdirigeras användaren till webbsidan för URL-förkortaren.
För gränssnittskod, kolla in GitHub-förrådet som nämns i slutet av det här inlägget. Det är i huvudsak ett textrutefält med en knapp för att skicka webbadressen till back-end och är utanför den här artikelns räckvidd.
Fler förbättringar av URL Shortener
Och vi är klara! Vi har en bara-bones URL-förkortare som kan användas internt för att förenkla dina länkar. Om du vill lägga till fler klockor och visselpipor, här är en lista över saker du kan implementera ytterligare:
- Bättre koddelning
- Bättre/anpassad förkortningsalgoritm för en mindre teckenhash (t.ex. base52)
- Dela förkortade webbadresser på sociala medier
- Kopiera webbadress med ett klick
- Anpassade hashar
- Användarregistrering och associerade förkortade webbadresser
Hela koden finns tillgänglig här: ScaleGrid URL Shortener Code Samples – Github En demoapplikation finns på Heroku:ScaleGrid URL Shortener Demo
Som alltid, om du bygger något fantastiskt, twittra oss om det @scalegridio. Om du behöver hjälp med hosting för MongoDB® eller hosting för Redis™*, kontakta oss på [email protected].