Node.js 实战:Koa 开发商城应用教程

欢迎阅读本文,本文将带领您实践 Koa 开发一个商城应用。在本文中,你将学习到:

  • Koa 中间件的概念及应用
  • 如何使用 Koa Router 实现 API 路由
  • MongoDB 数据库的使用及集合模型的设计
  • 基于 Koa 和 MongoDB 的商城应用开发实践

什么是 Koa

Koa 是一个基于 Node.js 平台的 Web 开发框架,由 Express 框架的原班人马打造。相比于 Express,Koa 更加轻量级,仅依赖少量的中间件,且采用了基于 async/await 的中间件机制,使得异步流程的处理更加清晰、优雅,因此备受开发者青睐。

Koa 中间件的概念及应用

在 Koa 中,中间件(Middleware)是一种处理 HTTP 请求的机制。它可以处理请求和响应,并将控制权交给下一个中间件或者应用程序。中间件可以是同步的函数,也可以是异步的。在 Koa 中,中间件是以函数的形式存在的。

Koa 的每一个请求,都要经过若干个中间件的处理,例如日志中间件、身份验证中间件、压缩中间件、路由中间件等等。Koa 提供了 app.use() 方法,通过链式调用,可以使用多个中间件,每个中间件对请求进行一些处理,再将请求传递给下一个中间件,形成中间件洋葱模型。

下面是一个简单的 Koa 中间件示例:

const Koa = require('koa');
const app = new Koa();

app.use(async (ctx, next) => {
  ctx.body = 'Hello World!';
  await next();
});

app.listen(3000, () => {
  console.log('server started at http://localhost:3000');
});

在上述代码中,通过 app.use() 添加了一个中间件函数,它的作用是将响应体设置成 Hello World!await next() 表示将控制权交给下一个中间件(如果存在的话),此处未使用下一个中间件。

如何使用 Koa Router 实现 API 路由

Koa Router 是一个专门用于处理 HTTP 请求的路由中间件。它支持路由参数、多个中间件、RESTful API 架构等。使用 Koa Router,我们可以方便地处理各种 HTTP 请求。

下面是一个使用 Koa Router 定义 RESTful API 的示例:

const Koa = require('koa');
const Router = require('@koa/router');
const app = new Koa();
const router = new Router();

// 获取所有商品
router.get('/api/products', async (ctx, next) => {
  // 查询 MongoDB 数据库,返回商品列表
  // ...
  ctx.response.body = products;
  await next();
});

// 获取单个商品
router.get('/api/products/:id', async (ctx, next) => {
  // 查询 MongoDB 数据库,返回指定商品
  // ...
  const id = ctx.params.id;
  ctx.response.body = product;
  await next();
});

// 添加商品
router.post('/api/products', async (ctx, next) => {
  // 解析请求体,插入 MongoDB 数据库
  // ...
  ctx.response.status = 201;
  ctx.response.body = product;
  await next();
});

// 删除商品
router.delete('/api/products/:id', async (ctx, next) => {
  // 删除 MongoDB 数据库中指定的商品
  // ...
  ctx.response.status = 204;
  await next();
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000, () => {
  console.log('server started at http://localhost:3000');
});

上述代码中,我们使用 router.get()router.post()router.delete() 等方法,分别定义了获取所有商品、获取单个商品、添加商品、删除商品等 RESTful API。router.allowedMethods() 中间件则用于处理 HTTP Status 405 和 501。

MongoDB 数据库的使用及集合模型的设计

MongoDB 是一个文档型数据库,使用它存储数据很方便。在实践中,我们可以使用 Mongoose ORM 定义数据模型、连接 MongoDB 数据库,并实现数据的 CRUD 操作。

下面是一个简单的商品数据模型示例:

const mongoose = require('mongoose');

// 商品数据模型
const productSchema = new mongoose.Schema({
  name: { type: String, required: true },
  price: { type: Number, required: true },
  description: { type: String, required: true },
  tags: { type: [String], default: [] },
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now },
});

module.exports = mongoose.model('Product', productSchema);

通过 mongoose.Schema 定义商品数据模型,包括商品名称、价格、描述、标签等字段。其中 required: true 表示该字段必填,type 表示字段的数据类型。使用 mongoose.model() 将模型与集合(Collection)关联起来。

现在,我们将上述模型集成到 Koa 应用中:

const Koa = require('koa');
const Router = require('@koa/router');
const mongoose = require('mongoose');
const Product = require('./models/product');
const app = new Koa();
const router = new Router();

mongoose.connect('mongodb://localhost:27017/koa-mall', { useNewUrlParser: true });

// 获取所有商品
router.get('/api/products', async (ctx, next) => {
  const products = await Product.find(); // 查询数据库
  ctx.response.body = products;
  await next();
});

// 获取单个商品
router.get('/api/products/:id', async (ctx, next) => {
  const id = ctx.params.id;
  const product = await Product.findById(id); // 查询数据库
  ctx.response.body = product;
  await next();
});

// 添加商品
router.post('/api/products', async (ctx, next) => {
  const product = await new Product(ctx.request.body).save(); // 插入数据库
  ctx.response.status = 201;
  ctx.response.body = product;
  await next();
});

// 删除商品
router.delete('/api/products/:id', async (ctx, next) => {
  const id = ctx.params.id;
  await Product.findByIdAndRemove(id); // 从数据库中删除
  ctx.response.status = 204;
  await next();
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000, () => {
  console.log('server started at http://localhost:3000');
});

在上述代码中,我们定义了 MongoDB 数据库的连接字符串,并使用 mongoose.connect() 方法连接数据库。在 RESTful API 中,使用 Product.find()Product.findById()new Product(ctx.request.body).save()Product.findByIdAndRemove(id) 等方法实现了数据的查询、插入、更新和删除等操作。

基于 Koa 和 MongoDB 的商城应用开发实践

现在,我们将 Koa 中间件、Koa Router 和 MongoDB 数据库集成起来,开发一个简单的商城应用。该应用中,我们实现了商品的列表展示、单个商品详情浏览、商品的添加、商品的删除等功能。对于各项功能的开发,我们在上前面部分中已经详细讲解过了,这里就直接呈现代码。

const Koa = require('koa');
const Router = require('@koa/router');
const mongoose = require('mongoose');
const Product = require('./models/product');
const app = new Koa();
const router = new Router();

mongoose.connect('mongodb://localhost:27017/koa-mall', { useNewUrlParser: true });

// 获取所有商品
router.get('/api/products', async (ctx, next) => {
  const products = await Product.find().sort('-createdAt'); // 查询并排序
  ctx.response.body = products;
  await next();
});

// 获取单个商品
router.get('/api/products/:id', async (ctx, next) => {
  const id = ctx.params.id;
  const product = await Product.findById(id); // 查询单个商品
  ctx.response.body = product;
  await next();
});

// 添加商品
router.post('/api/products', async (ctx, next) => {
  const product = await new Product(ctx.request.body).save(); // 插入商品
  ctx.response.status = 201;
  ctx.response.body = product;
  await next();
});

// 删除商品
router.delete('/api/products/:id', async (ctx, next) => {
  const id = ctx.params.id;
  await Product.findByIdAndRemove(id); // 删除指定 ID 的商品
  ctx.response.status = 204;
  await next();
});

// 主页
app.use(async (ctx, next) => {
  ctx.response.body = `
    <h1>Welcome to Koa Mall</h1>
    <p><a href="/products">View all products</a></p>
  `;
  await next();
});

// 商品列表页
app.use(async (ctx, next) => {
  if (ctx.request.url === '/products') {
    const products = await Product.find().sort('-createdAt'); // 查询并排序
    const productsHtml = products.map(product => `
      <li>
        <a href="/products/${product._id}">
          <h3>${product.name}</h3>
          <p>${product.description}</p>
        </a>
      </li>
    `).join('');
    ctx.response.body = `
      <h1>Products</h1>
      <ul>${productsHtml}</ul>
      <p><a href="/">Return to home page</a></p>
    `;
  } else {
    await next();
  }
});

// 商品详情页
app.use(async (ctx, next) => {
  if (ctx.request.url.startsWith('/products/')) {
    const id = ctx.request.url.split('/')[2];
    const product = await Product.findById(id); // 查询单个商品
    ctx.response.body = `
      <h1>${product.name}</h1>
      <p>${product.description}</p>
      <h3>$${product.price.toFixed(2)}</h3>
      <p><a href="/products">Return to product list</a></p>
      <form action="/products/${product._id}/delete" method="post">
        <button>Delete this product</button>
      </form>
    `;
  } else {
    await next();
  }
});

// 删除商品页
app.use(async (ctx, next) => {
  const referer = ctx.request.headers.referer || '/';
  if (ctx.request.url.startsWith('/products/') &&
      ctx.request.url.endsWith('/delete') &&
      ctx.request.method === 'POST') {
    const id = ctx.request.url.split('/')[2];
    await Product.findByIdAndRemove(id); // 删除商品
    ctx.response.redirect(referer); // 重定向到商品列表页
  } else {
    await next();
  }
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000, () => {
  console.log('server started at http://localhost:3000');
});

在上述代码中,我们使用了 mongoose 定义了商品数据模型并连接了 MongoDB 数据库。在 Koa 应用中,使用了 Koa Router 定义了 RESTful API,并为应用添加了多个中间件,包括主页、商品列表页、商品详情页、删除商品页等中间件。通过 Koa 应用,我们可以非常方便地开发复杂的商城应用,给用户提供更加完善的购物体验。

总结

本文介绍了使用 Koa 和 MongoDB 集成开发商城应用的全过程。在实践中,我们可以根据自己的需求,自定义数据模型、路由和中间件,完全掌握应用的开发过程。通过这篇文章的学习,相信读者已经对 Koa 中间件的概念和应用、MongoDB 数据库的使用和集合模型设计有了更加深入的理解,并能够实践开发一个基于 Koa 和 MongoDB 的商城应用。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a4eeb4add4f0e0ffd4a73c


纠错反馈