In dit bericht laten we je zien hoe je een URL-verkortingsservice zoals bit.ly of goo.gl bouwt met Express.js (Node.js) en MongoDB. Hier is een demo van het uiteindelijke product dat we gaan bouwen via ons MongoDB-hostingplatform.
Hoe werkt een URL-verkorter?
Op een zeer hoog niveau werkt de URL-verkorter door een ingevoerde URL te nemen en een relatief verkorte versie te maken, vereenvoudigd tot een gemakkelijk te delen formaat. De verkorte hash wordt gegenereerd door basiscodering van een automatisch oplopende teller en creëert een hash van minimaal drie tekens die toeneemt naarmate het aantal opgeslagen URL's toeneemt.
Wanneer de verkorte versie van de URL wordt bezocht, zal de service de hash decoderen om de originele URL op te halen die is opgeslagen in MongoDB en vervolgens uw gebruiker ernaar omleiden.
Aan de slag
Hier is een lijst van de technologieën die we zullen gebruiken om de URL-verkorter te bouwen in deze tutorial:
-
Express.js (Node.js-backend)
Een webapplicatie-framework voor Node.js. We zullen het gebruiken om een API te bouwen voor het inkorten van URL's en om gebruikers om te leiden naar de originele URL.
-
MongoDB (URL's opslaan)
Een NoSQL-database die perfect is voor deze app. Het biedt een flexibel schemaontwerp en is gemakkelijk om mee aan de slag te gaan. In deze zelfstudie gebruiken we een Shared MongoDB-cluster op ScaleGrid. Het instellen duurt minder dan 5 minuten en u kunt hier een gratis proefperiode van 30 dagen maken om aan de slag te gaan.
-
HTML, CSS, JavaScript (front-end)
HTML, CSS en JavaScript worden gebruikt om de front-end van de app te bouwen die uw gebruikers zullen gebruiken om URL's in te korten.
Zelfstudie URL-verkorting
-
De MongoDB-databasestructuur instellen
Laten we beginnen met het maken van een Shared MongoDB Cluster op ScaleGrid. Dit is de gemakkelijkste manier om snel een cluster te maken, maar u kunt ook MongoDB op uw computer installeren en daar aan de slag gaan.
Zodra het cluster is gemaakt, krijgt u een verbindingsreeks die met een enkele klik kan worden gekopieerd vanaf uw pagina Clusterdetails. We hebben deze tekenreeks nodig om vanuit onze toepassing verbinding te maken met het cluster. Denk eraan, deel uw verbindingsreeks nooit met iemand.
We hebben twee verzamelingen nodig voor de URL-verkorter:
-
Collectie 1
Een verzameling om de URL en dynamisch gegenereerde ID op te slaan:
-
Collectie 2
Een verzameling om de teller bij te houden die automatisch wordt verhoogd wanneer een nieuwe URL wordt opgeslagen in de vorige verzameling. Er wordt een nieuw document gemaakt in de vorige verzameling met deze nieuw verhoogde teller:
Het is belangrijk op te merken dat we de hashes nergens in de database opslaan. De hash wordt base-gecodeerd en dynamisch gedecodeerd met het algemene algoritme dat zal resulteren in de unieke ID die is opgeslagen in de eerste verzameling. Deze ID haalt dan de originele URL op waarnaar de gebruiker zal doorverwijzen.
Voor deze tutorial gebruiken we het algemene base64-coderings- en decoderingsmechanisme voor het genereren van onze unieke verkorte hash. Raadpleeg het volgende MDN-webdocument voor meer informatie over het coderen/decoderen van tekenreeksen met base64.
-
-
De Express.js-backend instellen
Hier is een lijst met afhankelijkheden die nodig zijn om onze Node.js-backend in te stellen:
- express (basis-app)
- body-parser (add-on voor het ontleden van gegevens verzonden via HTTP-verzoeken)
- btoa (base64-codering)
- atob (base64-decodering)
- dotenv (verbindingsreeks opslaan in een .env-bestand voor ontwikkelingsdoeleinden)
- mongoose (adapter voor MongoDB op Node.js)
Hier is een voorbeeldversie van package.json die u kunt gebruiken om de app in te stellen:
{ "name": "sg-url-shortener", "version": "1.0.0", "description": "A simple URL shortener built with Node.js and 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" } }
Voer "npm install" uit om alle vereiste afhankelijkheden te installeren.
Zodra al onze afhankelijkheden zijn ingesteld, moeten we verbinding maken met ons gedeelde MongoDB-cluster. Maak een .env-bestand in de hoofdmap van het project en voeg de verbindingsreeks eraan toe. U kunt de verbindingsreeks ophalen van uw pagina Clusterdetails op het tabblad Overzicht op de ScaleGrid-console.
connectionString=mongodb://user:password@devservers
Voordat we code gaan schrijven, is het een goede gewoonte om de app-stroom te visualiseren, zodat we een goed begrip hebben van hoe het verkortingsproces zal werken. Hier is een diagram dat het proces van URL-verkorting laat zien:
Hier is een diagram dat het proces van omleiding laat zien wanneer een verkorte URL wordt bezocht:
Nu we het hele proces hebben gevisualiseerd, is het tijd om de bovenstaande stroomdiagrammen in code te vertalen.
-
De toepassing initialiseren
Voordat we bedrijfslogica gaan schrijven, moeten we onze applicatie initialiseren met onze node-modules en een server opzetten.
Laad .env-bestanden alleen in dev-modus. Aangezien de demo-applicatie op Heroku wordt gehost, is er een omgevingsvariabele gemaakt op het Heroku-dashboard die daar al de verbindingsreeks bevat:
if(process.env.NODE_ENV !== 'production') { require('dotenv').load(); }
Initialisatie van de toepassing, server- en middleware-instellingen. Merk op dat we ook de verbindingsreeks krijgen van de omgevingsvariabele:
var express = require('express'), bodyParser = require('body-parser'), app = express(), http = require('http').Server(app), mongoose = require('mongoose'), btoa = require('btoa'), atob = require('atob'), promise, connectionString = process.env.connectionString, port = process.env.PORT || 8080; http.listen(port, function() { console.log('Server Started. Listening on *:' + port); }); app.use(express.static('public')); app.use(bodyParser.urlencoded({ extended: true }));
Basisroute voor het laden van de front-end van onze app:
app.get('/', function(req, res) { res.sendFile('views/index.html', { root: __dirname }); });
-
URL's opslaan in MongoDB
Laten we beginnen met het maken van de verzamelingsschema's voor het opslaan van gegevens. Zoals hierboven besproken, hebben we twee verzamelingen nodig:één voor het opslaan van de automatisch oplopende teller en de andere voor het opslaan van de URL's.
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);
De bovenstaande code maakt de twee collecties aan en stelt onze database in voor het opslaan van deze collecties. We gebruiken ook een pre-save hook voor het URL-schema, omdat we de teller automatisch moeten verhogen en de datum en tijd moeten loggen waarop de URL is gemaakt.
Vervolgens moeten we ervoor zorgen dat we onze applicatie opnieuw starten en dat alle eerdere vermeldingen worden verwijderd. Nadat we hebben gereset, initialiseren we onze teller met een startwaarde van 10.000 om het URL-verkortingsproces in te stellen. U kunt met elke waarde beginnen. Dit is willekeurig gekozen en wordt automatisch verhoogd met een waarde van één.
promise = mongoose.connect(connectionString, { useMongoClient: true }); promise.then(function(db) { console.log('connected!'); URL.remove({}, function() { console.log('URL collection removed'); }) Counter.remove({}, function() { console.log('Counter collection removed'); var counter = new Counter({_id: 'url_count', count: 10000}); counter.save(function(err) { if(err) return console.error(err); console.log('counter inserted'); }); }); });
Onze applicatie is nu klaar om URL's te accepteren en in te korten! Laten we een POST API maken die onze front-end zal gebruiken om de URL te verzenden:
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' }); }); } }); });
Zoals uiteengezet in het stroomdiagram, controleren we zodra een geldige URL is ontvangen of deze in de database aanwezig is.
Indien gevonden, decoderen we het corresponderende _id-veld en retourneren de hash terug. Onze front-end construeert de verkorte URL en presenteert deze aan de gebruiker voor omleiding.
Als er geen URL wordt gevonden, slaan we een nieuw document op in de collectie. Onthoud dat elke keer dat de URL wordt opgeslagen een pre-save-stap wordt uitgevoerd. Hierdoor wordt de teller automatisch verhoogd en worden de huidige datum en tijd geregistreerd. Nadat het document is toegevoegd, sturen we de hash naar onze front-end die de verkorte URL maakt en deze aan de gebruiker presenteert voor omleiding.
-
Gebruikers omleiden
We zijn bijna klaar! Zodra onze verkorte URL's zijn gemaakt, hebben we een manier nodig om de gebruiker om te leiden wanneer een verkorte URL wordt bezocht.
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('/'); } }); });
De bovenstaande code zoekt naar een hash in de verkorte URL, base64 decodeert deze, controleert of die ID in de collectie aanwezig is en leidt de gebruiker dienovereenkomstig om. Als er geen ID wordt gevonden, wordt de gebruiker doorgestuurd naar de startpagina van de URL-verkorter.
Bekijk voor front-end code de GitHub-repository die aan het einde van dit bericht wordt vermeld. Het is in wezen een tekstvak met een knop om de URL naar de back-end te sturen en valt buiten het bestek van dit artikel.
Meer verbeteringen aan URL-verkorters
En we zijn klaar! We hebben een eenvoudige URL-verkorter die intern kan worden gebruikt om uw links te vereenvoudigen. Als u meer toeters en bellen wilt toevoegen, volgt hier een lijst met dingen die u bovendien kunt implementeren:
- Beter code splitsen
- Beter/aangepast verkortingsalgoritme voor een hash van kleinere tekens (bijv. base52)
- Verkorte URL's delen op sociale media
- Een-klik URL kopiëren
- Aangepaste hashes
- Gebruikersregistratie en geassocieerde verkorte URL's
De volledige code is hier beschikbaar:ScaleGrid URL Shortener Code Samples – Github Een demo-applicatie wordt gehost op Heroku:ScaleGrid URL Shortener Demo
Zoals altijd, als je iets geweldigs bouwt, tweet ons er dan over @scalegridio. Als je hulp nodig hebt met hosting voor MongoDB® of hosting voor Redis™*, neem dan contact met ons op via [email protected].