Heim > Web-Frontend > js-Tutorial > Hauptteil

Ein vollständiges Beispiel für die gemeinsame Nutzung der RESTful-API-Implementierung von Node.js

黄舟
Freigeben: 2017-09-29 11:14:00
Original
2134 Leute haben es durchsucht

In diesem Artikel wird hauptsächlich ein Beispiel für die Implementierung einer vollständigen Node.js-RESTful-API vorgestellt. Der Herausgeber findet es recht gut, daher werde ich es jetzt mit Ihnen teilen und als Referenz verwenden. Folgen wir dem Editor und werfen wir einen Blick darauf.

Vorwort

Dieser Artikel ist eine Zusammenfassung des Buches Building APIs with Node.js. Das Schreiben von Schnittstellen mit Node.js ist für mich sehr nützlich. In der Anfangsphase des Projekts kann ich beispielsweise schnell Netzwerkanfragen simulieren. Gerade weil es in js geschrieben ist, ist seine direkte Verbindung zu iOS enger als die von Backends, die in anderen Sprachen geschrieben sind.

Dieses Buch ist sehr gut geschrieben und die Codierungsideen des Autors sind äußerst klar. Obwohl das gesamte Buch auf Englisch geschrieben ist, ist es leicht zu lesen. Gleichzeitig wird ein vollständiger Logiksatz für die RESTful-API erstellt.

Ich bevorzuge es, einige funktionale, responsive Programme zu schreiben. Die Übergabe von Funktionen als Daten oder Parameter ist für mich sehr attraktiv.

Von der Erstellung des Programms über den Entwurf des Fehlererkennungsmechanismus bis hin zum Testen des Programms ist dies ein vollständiger Prozess. Dieser Artikel wird sehr lang sein, ich werde den Code jedes Kernkonzepts einfügen.

Umgebungseinrichtung

Node.js https://nodejs.org/en/ herunterladen und installieren

npm installieren

Laden Sie das Demoprojekt herunter


git clone https://github.com/agelessman/ntask-api
Nach dem Login kopieren

Geben Sie den Projektordner ein und führen Sie


npm install
Nach dem Login kopieren
< aus 🎜 >Der obige Befehl lädt die für das Projekt erforderlichen Plug-Ins herunter und startet dann das Projekt



npm start
Nach dem Login kopieren
Zugriff auf das Schnittstellendokument http:// localhost:3000/apidoc

Programmeintrag

Es bietet viele Funktionen, die ich hier nicht erklären werde Zuerst den Code im Projekt:



import express from "express"
import consign from "consign"

const app = express();

/// 在使用include或者then的时候,是有顺序的,如果传入的参数是一个文件夹
/// 那么他会按照文件夹中文件的顺序进行加载
consign({verbose: false})
 .include("libs/config.js")
 .then("db.js")
 .then("auth.js")
 .then("libs/middlewares.js")
 .then("routers")
 .then("libs/boot.js")
 .into(app);

module.exports = app;
Nach dem Login kopieren
Ob es sich um Modelle, Ansichten oder Router handelt, sie werden von Express verarbeitet und konfiguriert. Ansichten werden in diesem Projekt nicht verwendet. Express konfiguriert die Funktionen des gesamten Projekts über die App. Wir können jedoch nicht alle Parameter und Methoden in diese Datei schreiben, da die Wartung sonst bei großen Projekten schwierig wird.

Ich habe sehr wenig Erfahrung mit Node.js, aber der obige Code vermittelt mir das Gefühl, dass er äußerst prägnant ist und die Ideen äußerst klar sind. Durch den Import anderer Module über das Consign-Modul sieht der Code sehr elegant aus .

@note: Die Reihenfolge des Imports ist wichtig.

Hier wird die App wie eine globale Variable verwendet, die wir im folgenden Inhalt zeigen werden. Nach dem sequenziellen Import können wir auf diese Weise auf den Inhalt des Moduls zugreifen:



app.db
app.auth
app.libs....
Nach dem Login kopieren

Modelldesign

Meiner Meinung nach ist die Anforderungsanalyse das Wichtigste, bevor wir mit jedem Projekt beginnen, nach der Anforderungsanalyse werden wir sie haben ein großes Konzept zum Code-Design.

Was ist die Essenz der Kodierung? Ich denke, es geht um die Speicherung und Übertragung von Daten, und wir müssen auch Leistungs- und Sicherheitsaspekte berücksichtigen

Daher besteht unsere zweite Aufgabe darin, ein Datenmodell zu entwerfen, das die Ergebnisse unserer Bedarfsanalyse widerspiegeln kann. In diesem Projekt gibt es zwei Modelle: Benutzer und Aufgabe. Jede Aufgabe entspricht einem Benutzer.

Benutzermodell:



import bcrypt from "bcrypt"

module.exports = (sequelize, DataType) => {
 "use strict";
 const Users = sequelize.define("Users", {
  id: {
   type: DataType.INTEGER,
   primaryKey: true,
   autoIncrement: true
  },
  name: {
   type: DataType.STRING,
   allowNull: false,
   validate: {
    notEmpty: true
   }
  },
  password: {
   type: DataType.STRING,
   allowNull: false,
   validate: {
    notEmpty: true
   }
  },
  email: {
   type: DataType.STRING,
   unique: true,
   allowNull: false,
   validate: {
    notEmpty: true
   }
  }
 }, {
  hooks: {
   beforeCreate: user => {
    const salt = bcrypt.genSaltSync();
    user.password = bcrypt.hashSync(user.password, salt);
   }
  }
 });
 Users.associate = (models) => {
  Users.hasMany(models.Tasks);
 };
 Users.isPassword = (encodedPassword, password) => {
  return bcrypt.compareSync(password, encodedPassword);
 };

 return Users;
};
Nach dem Login kopieren
Aufgabenmodell:



module.exports = (sequelize, DataType) => {
 "use strict";
 const Tasks = sequelize.define("Tasks", {
  id: {
   type: DataType.INTEGER,
   primaryKey: true,
   autoIncrement: true
  },
  title: {
   type: DataType.STRING,
   allowNull: false,
   validate: {
    notEmpty: true
   }
  },
  done: {
   type: DataType.BOOLEAN,
   allowNull: false,
   defaultValue: false
  }
 });
 Tasks.associate = (models) => {
  Tasks.belongsTo(models.Users);
 };
 return Tasks;
};
Nach dem Login kopieren
Dieses Projekt nutzt als Datenbank natürlich auch das mitgelieferte SQLite Datenbank verwendet werden, gibt es keine Einschränkung, ob sie relational oder nicht relational ist. Um die Daten besser verwalten zu können, verwenden wir das Sequelize-Modul zur Verwaltung der Datenbank.

Um Platz zu sparen, werde ich diese Module nicht vorstellen. Suchen Sie sie einfach bei Google und Sie werden sie finden. In der Entwicklung von Node.js, die ich gesehen habe, gibt es viele Verwaltungsmodule für diese Art von ORM, wie zum Beispiel mongoose, das MongoDB verwaltet. Es gibt viele, viele, und ihre Hauptidee ist Schema.

Im obigen Code haben wir die Ausgabe- und Eingabevorlagen des Modells definiert und einige spezifische Felder überprüft, sodass bei der Verwendung Fehler in der Datenbank auftreten können. Diese Fehler werden wir im Folgenden erläutern.



Tasks.associate = (models) => {
  Tasks.belongsTo(models.Users);
};

Users.associate = (models) => {
 Users.hasMany(models.Tasks);
};
Users.isPassword = (encodedPassword, password) => {
 return bcrypt.compareSync(password, encodedPassword);
};
Nach dem Login kopieren
hasMany undgehörtUm ein Assoziationsattribut darzustellen, und Users.isPassword ist eine Klassenmethode. Das bcrypt-Modul kann Passwörter verschlüsseln.

Datenbank

Wie wir oben bereits wissen, verwenden wir das Sequelize-Modul zur Verwaltung der Datenbank. Tatsächlich muss uns die Datenbank auf der einfachsten Ebene nur Datenmodelle zur Verfügung stellen. Nachdem wir diese Modelle erhalten haben, können wir verschiedene CRUD-Vorgänge je nach Bedarf ausführen.



import fs from "fs"
import path from "path"
import Sequelize from "sequelize"

let db = null;


module.exports = app => {
 "use strict";
 if (!db) {
  const config = app.libs.config;
  const sequelize = new Sequelize(
   config.database,
   config.username,
   config.password,
   config.params
  );

  db = {
   sequelize,
   Sequelize,
   models: {}
  };

  const dir = path.join(__dirname, "models");

  fs.readdirSync(dir).forEach(file => {
   const modelDir = path.join(dir, file);
   const model = sequelize.import(modelDir);
   db.models[model.name] = model;
  });

  Object.keys(db.models).forEach(key => {
   db.models[key].associate(db.models);
  });
 }
 return db;
};
Nach dem Login kopieren
Der obige Code ist sehr einfach, db ist ein Objekt, es speichert alle Modelle, in diesem Fall User und Task . Rufen Sie das Modell über sequelize.import ab und rufen Sie dann die zuvor geschriebene Associate-Methode auf.

Kehren Sie nach dem obigen Funktionsaufruf zur Datenbank zurück, die das von uns benötigte Modell enthält. An diesem Punkt haben wir eine Datenbankverbindung als Unterstützung für den folgenden Code hergestellt.

CRUD

CRUD ist im Router, schauen wir uns zuerst den Code von router/tasks.js an:



module.exports = app => {
 "use strict";
 const Tasks = app.db.models.Tasks;

 app.route("/tasks")
  .all(app.auth.authenticate())

  .get((req, res) => {
   console.log(`req.body: ${req.body}`);
   Tasks.findAll({where: {user_id: req.user.id} })
    .then(result => res.json(result))
    .catch(error => {
     res.status(412).json({msg: error.message});
    });
  })

  .post((req, res) => {
   req.body.user_id = req.user.id;
   Tasks.create(req.body)
    .then(result => res.json(result))
    .catch(error => {
     res.status(412).json({msg: error.message});
    });
  });

 app.route("/tasks/:id")
  .all(app.auth.authenticate())

  .get((req, res) => {
   Tasks.findOne({where: {
    id: req.params.id,
    user_id: req.user.id
   }})
    .then(result => {
     if (result) {
      res.json(result);
     } else {
      res.sendStatus(412);
     }
    })
    .catch(error => {
     res.status(412).json({msg: error.message});
    });
  })

  .put((req, res) => {
   Tasks.update(req.body, {where: {
    id: req.params.id,
    user_id: req.user.id
   }})
    .then(result => res.sendStatus(204))
    .catch(error => {
     res.status(412).json({msg: error.message});
    });
  })

  .delete((req, res) => {
   Tasks.destroy({where: {
    id: req.params.id,
    user_id: req.user.id
   }})
    .then(result => res.sendStatus(204))
    .catch(error => {
     res.status(412).json({msg: error.message});
    });
  });
};
Nach dem Login kopieren

再看看 router/users.js 的代码:


module.exports = app => {
 "use strict";
 const Users = app.db.models.Users;

 app.route("/user")
  .all(app.auth.authenticate())

 .get((req, res) => {
   Users.findById(req.user.id, {
    attributes: ["id", "name", "email"]
   })
    .then(result => res.json(result))
    .catch(error => {
     res.status(412).json({msg: error.message});
    });
  })

  .delete((req, res) => {
  console.log(`delete..........${req.user.id}`);
   Users.destroy({where: {id: req.user.id}})
    .then(result => {
     console.log(`result: ${result}`);
     return res.sendStatus(204);
    })
    .catch(error => {
     console.log(`resultfsaddfsf`);
     res.status(412).json({msg: error.message});
    });
  });

 app.post("/users", (req, res) => {
  Users.create(req.body)
   .then(result => res.json(result))
   .catch(error => {
    res.status(412).json({msg: error.message});
   });
 });
};
Nach dem Login kopieren

这些路由写起来比较简单,上边的代码中,基本思想就是根据模型操作CRUD,包括捕获异常。但是额外的功能是做了authenticate,也就是授权操作。

这一块好像没什么好说的,基本上都是固定套路。

授权

在网络环境中,不能老是传递用户名和密码。这时候就需要一些授权机制,该项目中采用的是JWT授权(JSON Wbb Toknes),有兴趣的同学可以去了解下这个授权,它也是按照一定的规则生成token。

因此对于授权而言,最核心的部分就是如何生成token。


import jwt from "jwt-simple"

module.exports = app => {
 "use strict";
 const cfg = app.libs.config;
 const Users = app.db.models.Users;

 app.post("/token", (req, res) => {
  const email = req.body.email;
  const password = req.body.password;
  if (email && password) {
   Users.findOne({where: {email: email}})
    .then(user => {
     if (Users.isPassword(user.password, password)) {
      const payload = {id: user.id};
      res.json({
       token: jwt.encode(payload, cfg.jwtSecret)
      });
     } else {
      res.sendStatus(401);
     }
    })
    .catch(error => res.sendStatus(401));
  } else {
   res.sendStatus(401);
  }
 });
};
Nach dem Login kopieren

上边代码中,在得到邮箱和密码后,再使用 jwt-simple 模块生成一个token。

JWT在这也不多说了,它由三部分组成,这个在它的官网中解释的很详细。

我觉得老外写东西一个最大的优点就是文档很详细。要想弄明白所有组件如何使用,最好的方法就是去他们的官网看文档,当然这要求英文水平还可以。

授权一般分两步:

  • 生成token

  • 验证token

如果从前端传递一个token过来,我们怎么解析这个token,然后获取到token里边的用户信息呢?


import passport from "passport";
import {Strategy, ExtractJwt} from "passport-jwt";

module.exports = app => {
 const Users = app.db.models.Users;
 const cfg = app.libs.config;
 const params = {
  secretOrKey: cfg.jwtSecret,
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
 };
 var opts = {};
 opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("JWT");
 opts.secretOrKey = cfg.jwtSecret;

 const strategy = new Strategy(opts, (payload, done) => {
  Users.findById(payload.id)
   .then(user => {
    if (user) {
     return done(null, {
      id: user.id,
      email: user.email
     });
    }
    return done(null, false);
   })
   .catch(error => done(error, null));
 });
 passport.use(strategy);

 return {
  initialize: () => {
   return passport.initialize();
  },
  authenticate: () => {
   return passport.authenticate("jwt", cfg.jwtSession);
  }
 };
};
Nach dem Login kopieren

这就用到了 passport 和 passport-jwt 这两个模块。 passport 支持很多种授权。不管是iOS还是Node中,验证都需要指定一个策略,这个策略是最灵活的一层。

授权需要在项目中提前进行配置,也就是初始化, app.use(app.auth.initialize()); 。

如果我们想对某个接口进行授权验证,那么只需要像下边这么用就可以了:


.all(app.auth.authenticate())

.get((req, res) => {
 console.log(`req.body: ${req.body}`);
 Tasks.findAll({where: {user_id: req.user.id} })
  .then(result => res.json(result))
  .catch(error => {
   res.status(412).json({msg: error.message});
  });
})
Nach dem Login kopieren

配置

Node.js中一个很有用的思想就是middleware,我们可以利用这个手段做很多有意思的事情:


import bodyParser from "body-parser"
import express from "express"
import cors from "cors"
import morgan from "morgan"
import logger from "./logger"
import compression from "compression"
import helmet from "helmet"

module.exports = app => {
 "use strict";
 app.set("port", 3000);
 app.set("json spaces", 4);
 console.log(`err ${JSON.stringify(app.auth)}`);
 app.use(bodyParser.json());
 app.use(app.auth.initialize());
 app.use(compression());
 app.use(helmet());
 app.use(morgan("common", {
  stream: {
   write: (message) => {
    logger.info(message);
   }
  }
 }));
 app.use(cors({
  origin: ["http://localhost:3001"],
  methods: ["GET", "POST", "PUT", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"]
 }));
 app.use((req, res, next) => {
  // console.log(`header: ${JSON.stringify(req.headers)}`);
  if (req.body && req.body.id) {
   delete req.body.id;
  }
  next();
 });

 app.use(express.static("public"));
};
Nach dem Login kopieren

上边的代码中包含了很多新的模块,app.set表示进行设置,app.use表示使用middleware。

测试

写测试代码是我平时很容易疏忽的地方,说实话,这么重要的部分不应该被忽视。


import jwt from "jwt-simple"

describe("Routes: Users", () => {
 "use strict";
 const Users = app.db.models.Users;
 const jwtSecret = app.libs.config.jwtSecret;
 let token;

 beforeEach(done => {
  Users
   .destroy({where: {}})
   .then(() => {
    return Users.create({
     name: "Bond",
     email: "Bond@mc.com",
     password: "123456"
    });
   })
   .then(user => {
    token = jwt.encode({id: user.id}, jwtSecret);
    done();
   });
 });

 describe("GET /user", () => {
  describe("status 200", () => {
   it("returns an authenticated user", done => {
    request.get("/user")
     .set("Authorization", `JWT ${token}`)
     .expect(200)
     .end((err, res) => {
      expect(res.body.name).to.eql("Bond");
      expect(res.body.email).to.eql("Bond@mc.com");
      done(err);
     });
   });
  });
 });

 describe("DELETE /user", () => {
  describe("status 204", () => {
   it("deletes an authenticated user", done => {
    request.delete("/user")
     .set("Authorization", `JWT ${token}`)
     .expect(204)
     .end((err, res) => {
      console.log(`err: ${err}`);
      done(err);
     });
   });
  });
 });

 describe("POST /users", () => {
  describe("status 200", () => {
   it("creates a new user", done => {
    request.post("/users")
     .send({
      name: "machao",
      email: "machao@mc.com",
      password: "123456"
     })
     .expect(200)
     .end((err, res) => {
      expect(res.body.name).to.eql("machao");
      expect(res.body.email).to.eql("machao@mc.com");
      done(err);
     });
   });
  });
 });
});
Nach dem Login kopieren

测试主要依赖下边的这几个模块:


import supertest from "supertest"
import chai from "chai"
import app from "../index"

global.app = app;
global.request = supertest(app);
global.expect = chai.expect;
Nach dem Login kopieren

其中 supertest 用来发请求的, chai 用来判断是否成功。

使用 mocha 测试框架来进行测试:


"test": "NODE_ENV=test mocha test/**/*.js",
Nach dem Login kopieren

生成接口文档

接口文档也是很重要的一个环节,该项目使用的是 ApiDoc.js 。这个没什么好说的,直接上代码:


/**
 * @api {get} /tasks List the user&#39;s tasks
 * @apiGroup Tasks
 * @apiHeader {String} Authorization Token of authenticated user
 * @apiHeaderExample {json} Header
 * {
 *  "Authorization": "xyz.abc.123.hgf"
 * }
 * @apiSuccess {Object[]} tasks Task list
 * @apiSuccess {Number} tasks.id Task id
 * @apiSuccess {String} tasks.title Task title
 * @apiSuccess {Boolean} tasks.done Task is done?
 * @apiSuccess {Date} tasks.updated_at Update&#39;s date
 * @apiSuccess {Date} tasks.created_at Register&#39;s date
 * @apiSuccess {Number} tasks.user_id The id for the user&#39;s
 * @apiSuccessExample {json} Success
 * HTTP/1.1 200 OK
 * [{
 *  "id": 1,
 *  "title": "Study",
 *  "done": false,
 *  "updated_at": "2016-02-10T15:46:51.778Z",
 *  "created_at": "2016-02-10T15:46:51.778Z",
 *  "user_id": 1
 * }]
 * @apiErrorExample {json} List error
 * HTTP/1.1 412 Precondition Failed
 */
 
 /**
 * @api {post} /users Register a new user
 * @apiGroup User
 * @apiParam {String} name User name
 * @apiParam {String} email User email
 * @apiParam {String} password User password
 * @apiParamExample {json} Input
 * {
 *  "name": "James",
 *  "email": "James@mc.com",
 *  "password": "123456"
 * }
 * @apiSuccess {Number} id User id
 * @apiSuccess {String} name User name
 * @apiSuccess {String} email User email
 * @apiSuccess {String} password User encrypted password
 * @apiSuccess {Date} update_at Update&#39;s date
 * @apiSuccess {Date} create_at Rigister&#39;s date
 * @apiSuccessExample {json} Success
 * {
 *  "id": 1,
 *  "name": "James",
 *  "email": "James@mc.com",
 *  "updated_at": "2016-02-10T15:20:11.700Z",
 *  "created_at": "2016-02-10T15:29:11.700Z"
 * }
 * @apiErrorExample {json} Rergister error
 * HTTP/1.1 412 Precondition Failed
 */
Nach dem Login kopieren

大概就类似与上边的样子,既可以做注释用,又可以自动生成文档,一石二鸟,我就不上图了。

准备发布

到了这里,就只剩下发布前的一些操作了,

有的时候,处于安全方面的考虑,我们的API可能只允许某些域名的访问,因此在这里引入一个强大的模块 cors ,介绍它的文章,网上有很多,大家可以直接搜索,在该项目中是这么使用的:


app.use(cors({
 origin: ["http://localhost:3001"],
 methods: ["GET", "POST", "PUT", "DELETE"],
 allowedHeaders: ["Content-Type", "Authorization"]
}));
Nach dem Login kopieren

这个设置在本文的最后的演示网站中,会起作用。

打印请求日志同样是一个很重要的任务,因此引进了 winston 模块。下边是对他的配置:


import fs from "fs"
import winston from "winston"

if (!fs.existsSync("logs")) {
 fs.mkdirSync("logs");
}

module.exports = new winston.Logger({
 transports: [
  new winston.transports.File({
   level: "info",
   filename: "logs/app.log",
   maxsize: 1048576,
   maxFiles: 10,
   colorize: false
  })
 ]
});
Nach dem Login kopieren

打印的结果大概是这样的:


{"level":"info","message":"::1 - - [26/Sep/2017:11:16:23 +0000] \"GET /tasks HTTP/1.1\" 200 616\n","timestamp":"2017-09-26T11:16:23.089Z"}
{"level":"info","message":"::1 - - [26/Sep/2017:11:16:43 +0000] \"OPTIONS /user HTTP/1.1\" 204 0\n","timestamp":"2017-09-26T11:16:43.583Z"}
{"level":"info","message":"Tue Sep 26 2017 19:16:43 GMT+0800 (CST) Executing (default): SELECT `id`, `name`, `password`, `email`, `created_at`, `updated_at` FROM `Users` AS `Users` WHERE `Users`.`id` = 342;","timestamp":"2017-09-26T11:16:43.592Z"}
{"level":"info","message":"Tue Sep 26 2017 19:16:43 GMT+0800 (CST) Executing (default): SELECT `id`, `name`, `email` FROM `Users` AS `Users` WHERE `Users`.`id` = 342;","timestamp":"2017-09-26T11:16:43.596Z"}
{"level":"info","message":"::1 - - [26/Sep/2017:11:16:43 +0000] \"GET /user HTTP/1.1\" 200 73\n","timestamp":"2017-09-26T11:16:43.599Z"}
{"level":"info","message":"::1 - - [26/Sep/2017:11:16:49 +0000] \"OPTIONS /user HTTP/1.1\" 204 0\n","timestamp":"2017-09-26T11:16:49.658Z"}
{"level":"info","message":"Tue Sep 26 2017 19:16:49 GMT+0800 (CST) Executing (default): SELECT `id`, `name`, `password`, `email`, `created_at`, `updated_at` FROM `Users` AS `Users` WHERE `Users`.`id` = 342;","timestamp":"2017-09-26T11:16:49.664Z"}
{"level":"info","message":"Tue Sep 26 2017 19:16:49 GMT+0800 (CST) Executing (default): DELETE FROM `Users` WHERE `id` = 342","timestamp":"2017-09-26T11:16:49.669Z"}
{"level":"info","message":"::1 - - [26/Sep/2017:11:16:49 +0000] \"DELETE /user HTTP/1.1\" 204 -\n","timestamp":"2017-09-26T11:16:49.714Z"}
{"level":"info","message":"::1 - - [26/Sep/2017:11:17:04 +0000] \"OPTIONS /token HTTP/1.1\" 204 0\n","timestamp":"2017-09-26T11:17:04.905Z"}
{"level":"info","message":"Tue Sep 26 2017 19:17:04 GMT+0800 (CST) Executing (default): SELECT `id`, `name`, `password`, `email`, `created_at`, `updated_at` FROM `Users` AS `Users` WHERE `Users`.`email` = &#39;xiaoxiao@mc.com&#39; LIMIT 1;","timestamp":"2017-09-26T11:17:04.911Z"}
{"level":"info","message":"::1 - - [26/Sep/2017:11:17:04 +0000] \"POST /token HTTP/1.1\" 401 12\n","timestamp":"2017-09-26T11:17:04.916Z"}
Nach dem Login kopieren

性能上,我们使用Node.js自带的cluster来利用机器的多核,代码如下:


import cluster from "cluster"
import os from "os"

const CPUS = os.cpus();

if (cluster.isMaster) {
 // Fork
 CPUS.forEach(() => cluster.fork());

 // Listening connection event
 cluster.on("listening", work => {
  "use strict";
  console.log(`Cluster ${work.process.pid} connected`);
 });

 // Disconnect
 cluster.on("disconnect", work => {
  "use strict";
  console.log(`Cluster ${work.process.pid} disconnected`);
 });

 // Exit
 cluster.on("exit", worker => {
  "use strict";
  console.log(`Cluster ${worker.process.pid} is dead`);
  cluster.fork();
 });

} else {
 require("./index");
}
Nach dem Login kopieren

在数据传输上,我们使用 compression 模块对数据进行了gzip压缩,这个使用起来比较简单:


app.use(compression());
Nach dem Login kopieren

最后,让我们支持https访问,https的关键就在于证书,使用授权机构的证书是最好的,但该项目中,我们使用http://www.selfsignedcertificate.com这个网站自动生成了一组证书,然后启用https的服务:


import https from "https"
import fs from "fs"

module.exports = app => {
 "use strict";
 if (process.env.NODE_ENV !== "test") {

  const credentials = {
   key: fs.readFileSync("44885970_www.localhost.com.key", "utf8"),
   cert: fs.readFileSync("44885970_www.localhost.com.cert", "utf8")
  };

  app.db.sequelize.sync().done(() => {

   https.createServer(credentials, app)
    .listen(app.get("port"), () => {
    console.log(`NTask API - Port ${app.get("port")}`);
   });
  });
 }
};
Nach dem Login kopieren

当然,处于安全考虑,防止攻击,我们使用了 helmet 模块:


app.use(helmet());
Nach dem Login kopieren

前端程序

为了更好的演示该API,我把前段的代码也上传到了这个仓库https://github.com/agelessman/ntaskWeb,直接下载后,运行就行了。

API的代码连接https://github.com/agelessman/ntask-api

总结

我觉得这本书写的非常好,我收获很多。它虽然并不复杂,但是该有的都有了,因此我可以自由的往外延伸。同时也学到了作者驾驭代码的能力。

Ich habe das Gefühl, dass ich noch nicht in der Lage bin, klar zu erklären, was ich gelernt habe. Sollten Fehler vorhanden sein, korrigieren Sie diese bitte.

Das obige ist der detaillierte Inhalt vonEin vollständiges Beispiel für die gemeinsame Nutzung der RESTful-API-Implementierung von Node.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage