You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MongoDB中存储URL并在Node.js网站代码中实现重定向与用户专属PDF下载功能

Hey there! Let's break down how to solve both of these requirements step by step using your MongoDB + Node.js + HTML/CSS stack. I'll cover database design, backend logic, and frontend implementation for each need.

需求1:存储外部URL到MongoDB并实现页面重定向

1. MongoDB 数据模型设计

First off, we'll create a collection to store the external URLs. Let's call it redirectLinks—using Mongoose (the most common ODM for Node.js + MongoDB) to define the schema makes this straightforward:

// models/RedirectLink.js
const mongoose = require('mongoose');

const redirectLinkSchema = new mongoose.Schema({
  originalUrl: {
    type: String,
    required: true,
    trim: true,
    validate: {
      validator: (value) => {
        // Basic URL validation to ensure it starts with http/https
        return /^(https?:\/\/)/.test(value);
      },
      message: 'Please enter a valid external URL starting with http:// or https://'
    }
  },
  slug: {
    type: String,
    unique: true,
    trim: true,
    default: () => Math.random().toString(36).substring(2, 8) // Generate random short identifier
  },
  createdAt: {
    type: Date,
    default: Date.now
  }
});

module.exports = mongoose.model('RedirectLink', redirectLinkSchema);

The slug field gives you a clean, user-friendly path for redirects (like yourdomain.com/go/abc123) instead of using the MongoDB _id directly.

2. Node.js 后端实现 (Express)

Next, build two core endpoints: one to save the external URL to the database, and another to handle the actual redirect.

2.1 保存URL的接口

// routes/redirectRoutes.js
const express = require('express');
const router = express.Router();
const RedirectLink = require('../models/RedirectLink');

// Save a new external URL and return the redirect path
router.post('/save-url', async (req, res) => {
  try {
    const { originalUrl } = req.body;
    const link = new RedirectLink({ originalUrl });
    await link.save();
    res.status(201).json({
      success: true,
      redirectPath: `/go/${link.slug}`
    });
  } catch (err) {
    res.status(400).json({ success: false, message: err.message });
  }
});

2.2 重定向接口

// Handle the redirect logic
router.get('/go/:slug', async (req, res) => {
  try {
    const { slug } = req.params;
    const link = await RedirectLink.findOne({ slug });
    
    if (!link) {
      return res.status(404).send('Redirect link not found');
    }

    // Use 302 for temporary redirects, 301 for permanent ones
    res.redirect(302, link.originalUrl);
  } catch (err) {
    res.status(500).send('Server error');
  }
});

module.exports = router;

Don't forget to register this router in your main Express app:

// app.js
const redirectRoutes = require('./routes/redirectRoutes');
app.use('/', redirectRoutes);

3. 前端实现

Create a simple form to submit URLs and display the generated redirect link:

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
  <title>URL Redirect Manager</title>
  <style>
    .container { max-width: 600px; margin: 2rem auto; padding: 0 1rem; }
    input, button { padding: 0.8rem; margin: 0.5rem 0; width: 100%; box-sizing: border-box; }
    .redirect-link { margin-top: 1rem; padding: 1rem; background: #f0f0f0; border-radius: 4px; }
  </style>
</head>
<body>
  <div class="container">
    <h2>Save External URL for Redirect</h2>
    <form id="urlForm">
      <input type="url" id="originalUrl" placeholder="Enter external URL (http://...)" required>
      <button type="submit">Save & Generate Redirect Link</button>
    </form>
    <div id="result" class="redirect-link" style="display: none;"></div>
  </div>

  <script>
    const form = document.getElementById('urlForm');
    const resultDiv = document.getElementById('result');

    form.addEventListener('submit', async (e) => {
      e.preventDefault();
      const originalUrl = document.getElementById('originalUrl').value;

      try {
        const res = await fetch('/save-url', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ originalUrl })
        });
        const data = await res.json();
        
        if (data.success) {
          resultDiv.style.display = 'block';
          resultDiv.innerHTML = `Redirect link: <a href="${data.redirectPath}" target="_blank">${window.location.origin}${data.redirectPath}</a>`;
        } else {
          alert(data.message);
        }
      } catch (err) {
        alert('Failed to save URL. Please try again.');
      }
    });
  </script>
</body>
</html>
需求2:用户专属PDF下载功能

This one ties into user authentication, so I'll assume you already have a User collection set up (if not, I'll include a basic schema below).

1. MongoDB 数据模型设计

We have two scalable options here:

  • Option 1: Add a pdfUrl field directly to your existing User schema (simple for single PDF per user)
  • Option 2: Create a separate UserDocument collection (better if users might have multiple PDFs later)

Let's go with Option 2 for future flexibility:

1.1 User Schema (if you don't have one)

// models/User.js
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  name: { type: String, required: true },
  createdAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model('User', userSchema);

1.2 UserDocument Schema

// models/UserDocument.js
const mongoose = require('mongoose');

const userDocumentSchema = new mongoose.Schema({
  userId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  pdfUrl: {
    type: String,
    required: true,
    trim: true
  },
  fileName: {
    type: String,
    required: true,
    trim: true
  },
  createdAt: { type: Date, default: Date.now }
});

// Add index to speed up user-specific queries
userDocumentSchema.index({ userId: 1 });

module.exports = mongoose.model('UserDocument', userDocumentSchema);

2. Node.js 后端实现

First, we'll set up JWT authentication (the standard for Node.js apps) to protect the PDF endpoint.

2.1 Authentication Middleware

// middleware/auth.js
const jwt = require('jsonwebtoken');
const User = require('../models/User');

const authenticateUser = async (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1]; // Extract token from "Bearer <token>"

  if (!token) {
    return res.status(401).json({ message: 'Authentication required' });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET); // Use your secret from environment variables
    req.user = await User.findById(decoded.userId).select('-password'); // Exclude password from user object
    next();
  } catch (err) {
    res.status(401).json({ message: 'Invalid or expired token' });
  }
};

module.exports = authenticateUser;

2.2 Endpoints

2.2.1 Login Endpoint (to get JWT token)

// routes/authRoutes.js
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');

router.post('/login', async (req, res) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email });

    if (!user) {
      return res.status(400).json({ message: 'Invalid credentials' });
    }

    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
      return res.status(400).json({ message: 'Invalid credentials' });
    }

    // Generate JWT token valid for 24 hours
    const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: '24h' });
    res.json({ success: true, token, userId: user._id });
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;

2.2.2 Get User's PDF URL

// routes/userDocumentRoutes.js
const express = require('express');
const router = express.Router();
const authenticateUser = require('../middleware/auth');
const UserDocument = require('../models/UserDocument');

// Fetch the user's exclusive PDF
router.get('/my-pdf', authenticateUser, async (req, res) => {
  try {
    const document = await UserDocument.findOne({ userId: req.user._id });

    if (!document) {
      return res.status(404).json({ message: 'No PDF found for your account' });
    }

    res.json({
      success: true,
      pdfUrl: document.pdfUrl,
      fileName: document.fileName
    });
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;

Register these routes in your main app:

// app.js
const authRoutes = require('./routes/authRoutes');
const userDocumentRoutes = require('./routes/userDocumentRoutes');

app.use('/auth', authRoutes);
app.use('/documents', userDocumentRoutes);

3. 前端实现

Create a login page, and after successful authentication, a page with the personalized PDF download button:

3.1 Login Page

<!-- login.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Login</title>
  <style>
    .container { max-width: 400px; margin: 2rem auto; padding: 0 1rem; }
    input, button { padding: 0.8rem; margin: 0.5rem 0; width: 100%; box-sizing: border-box; border-radius: 4px; border: 1px solid #ddd; }
    button { background: #007bff; color: white; border: none; cursor: pointer; }
    button:hover { background: #0056b3; }
  </style>
</head>
<body>
  <div class="container">
    <h2>Login to Access Your PDF</h2>
    <form id="loginForm">
      <input type="email" id="email" placeholder="Enter your email" required>
      <input type="password" id="password" placeholder="Enter your password" required>
      <button type="submit">Login</button>
    </form>
  </div>

  <script>
    const form = document.getElementById('loginForm');

    form.addEventListener('submit', async (e) => {
      e.preventDefault();
      const email = document.getElementById('email').value;
      const password = document.getElementById('password').value;

      try {
        const res = await fetch('/auth/login', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ email, password })
        });
        const data = await res.json();
        
        if (data.success) {
          localStorage.setItem('token', data.token);
          window.location.href = '/pdf-download.html';
        } else {
          alert(data.message);
        }
      } catch (err) {
        alert('Login failed. Please try again.');
      }
    });
  </script>
</body>
</html>

3.2 PDF Download Page

<!-- pdf-download.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Your Exclusive PDF</title>
  <style>
    .container { max-width: 600px; margin: 2rem auto; padding: 0 1rem; text-align: center; }
    .download-btn {
      padding: 1rem 2rem;
      background: #28a745;
      color: white;
      border: none;
      border-radius: 4px;
      font-size: 1.1rem;
      cursor: pointer;
      text-decoration: none;
      display: inline-block;
      margin-top: 2rem;
    }
    .download-btn:hover { background: #218838; }
    .error { color: #dc3545; margin-top: 2rem; }
  </style>
</head>
<body>
  <div class="container">
    <h2>Welcome, Your PDF is Ready!</h2>
    <div id="downloadSection" style="display: none;">
      <a id="pdfLink" class="download-btn" href="#" download>Download Your PDF</a>
    </div>
    <div id="errorMsg" class="error" style="display: none;"></div>
  </div>

  <script>
    window.addEventListener('load', async () => {
      const token = localStorage.getItem('token');
      if (!token) {
        window.location.href = '/login.html';
        return;
      }

      try {
        const res = await fetch('/documents/my-pdf', {
          headers: { 'Authorization': `Bearer ${token}` }
        });
        const data = await res.json();
        
        if (data.success) {
          const pdfLink = document.getElementById('pdfLink');
          pdfLink.href = data.pdfUrl;
          pdfLink.download = data.fileName; // Forces download instead of opening in browser
          document.getElementById('downloadSection').style.display = 'block';
        } else {
          document.getElementById('errorMsg').textContent = data.message;
          document.getElementById('errorMsg').style.display = 'block';
        }
      } catch (err) {
        document.getElementById('errorMsg').textContent = 'Failed to load your PDF. Please try again later.';
        document.getElementById('errorMsg').style.display = 'block';
      }
    });
  </script>
</body>
</html>

Quick Security & Best Practice Notes

  • Always use environment variables (with dotenv package) for sensitive data like JWT secrets and MongoDB URIs.
  • For PDF storage, use cloud services like AWS S3 or Google Cloud Storage, and store signed/public URLs in MongoDB. Avoid storing PDFs directly in the database.
  • Hash user passwords before saving them to MongoDB (use bcryptjs as shown in the login endpoint).

内容的提问来源于stack exchange,提问作者Sahil Jeet Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 22:22:44