[譯] 化 Markdown 爲 HTML:用 Node.js 和 Express 搭建接口

快速摘要:搭建一個把 Markdown 語法轉換爲 HTML 的應用,經過該實踐來學習如何使用 Node.js 和 Express 框架建立接口端點。javascript

Markdown 是一種輕量級的文本標記語言,能將帶標記的文本轉換爲各類格式。發明 Markdown 的初衷,是爲了讓人們能「用易讀易寫的純文本格式來書寫」,並能夠按需轉換爲有效的 XHTML(或者 HTML)。目前,隨着 WordPress 的支持,Markdown 語法愈來愈流行了。html

本文旨在向讀者展現如何用 Node.js 和 Express 框架建立接口端點。咱們會搭建一個將 Markdown 轉換爲 HTML 的應用,在搭建過程當中學習 Node.js 和 Express。咱們還會給接口添加驗證機制,以防咱們的應用被濫用。前端

一個基於 Node.js 的 Markdown 應用

咱們把這個小巧玲瓏的應用叫作 「Markdown 轉換器」,咱們把 Markdown 語法的文本上傳給它,而後獲得 HTML 格式的版本。該應用使用 Node.js 的框架 Express 實現,並支持對轉換請求的驗證。java

咱們會化整爲零地實現這個應用 —— 先用 Express 建立一個基本框架,而後再添加驗證機制等功能。那就讓咱們開始搭建基本框架吧!node

第一階段:初始化 Express

假設你已經在操做系統裏安裝了 Node.js,如今咱們建立一個文件夾(就叫它 「markdown-api」 吧)來存放代碼,並進入該文件夾:android

$ mkdir markdown-api
$ cd markdown-api
複製代碼

使用 npm init 命令建立一個 package.json 文件。該命令會提示你輸入諸如應用名稱、版本之類的信息。ios

就本次實踐來講,你只需按下 Enter 鍵使用那些默認信息就好。我把 index.js 作爲默認入口文件,但你也能夠按本身喜愛設置成 app.js 或別的文件。git

如今咱們在 markdown-api 目錄下安裝 Express,並將其列入依賴包列表:github

$ npm install express --save
複製代碼

在當前目錄(markdown-api)建立一個 index.js 文件,把下列代碼添加進去來測試 Express 框架是否安裝成功:web

const express = require('express');
var app = express();
 
app.get('/', function(req, res){
    res.send('Hello World!');
});
 
app.listen(3000);
複製代碼

訪問 http://localhost:3000 ,看看測試文件是否成功運行起來了。若是一切順利,咱們能在瀏覽器中看到 「Hello World!」 字樣,那接下來就能夠構建 Markdown 轉 HTML 的基本接口了。

第二階段:構建基本接口

該接口的主要做用是把 Markdown 轉爲 HTML,它將有兩個端點:

  • /login
  • /convert

login 端點用來驗證有效請求;convert 端點用來進行 Markdown 到 HTML 的轉換。

如下是調用兩個端點的基本接口代碼。調用 login 會返回一個 「Authenticated」 字符串,而調用 convert 會返回你上傳的 Markdown 文本。主方法僅返回一個 「Hello World!」 字符串。

const express = require("express");
const bodyParser = require('body-parser');
    
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
 
app.get('/', function(req, res){
    res.send('Hello World!');
});
 
app.post('/login', function(req, res) {
    res.send("Authenticated");
  },
);
 
app.post("/convert", function(req, res, next) {
    console.log(req.body);
    if(typeof req.body.content == 'undefined' || req.body.content == null) {
        res.json(["error", "No data found"]);
    } else {
        res.json(["markdown", req.body.content]);
    }
});
 
app.listen(3000, function() {
 console.log("Server running on port 3000");
});
複製代碼

咱們使用中間件 body-parser 來輔助解析收到的請求。該中間件將解析結果放在 req.body 屬性中供你使用。雖然說不借助中間件也能解析請求,但那樣就太麻煩了。

用 npm 就能夠安裝 body-parser

$ npm install body-parser
複製代碼

如今萬事俱備,咱們得用 Postman 測試一下。先簡單介紹一下 Postman 吧。

Postman 簡介

Postman 是一種接口開發工具,使用其網頁版或者桌面客戶端(網頁版下架了)能夠極爲方便地搭建、修改以及測試接口端點。它能夠生成各類類型的 HTTP 請求,例如 GET、POST、PUT 和 PATCH。Postman 支持 Windows、macOS 和 Linux。

來一睹 Postman 的風采吧:

Postman 的界面

高清大圖

要想調用一個接口端點,你須要遵循如下步驟:

  1. 在頂部的地址欄輸入目標 URL;
  2. 在地址欄左側選擇 HTTP 方法;
  3. 點擊「發送」按鈕。

Postman 會把請求發送給應用,取得響應信息並顯示在界面下方的窗口中。這就是 Postman 的基本用法。在咱們的應用中,咱們還要給請求添加其餘參數,這一塊內容後面會說到。

使用 Postman

大概熟悉了 Postman 以後,咱們就要實際使用它了。

用命令行啓動 markdown-api 應用:

$ node index.js
複製代碼

爲了測試基本接口代碼,咱們要用 Postman 調用接口。注意,咱們用 POST 方法把要轉換的文本傳給應用。

咱們的應用經過 POST 方法的 content 參數接收待轉換的文本。咱們把它做爲 URL 編碼格式傳遞。字符串以 JSON 的格式返回 —— 第一個字段總會返回字符串 markdown,而第二個字段返回轉換後的文本。而後,當咱們添加了 Markdown 處理代碼,它就會返回轉換後的文本。

第三階段:添加 Markdown 轉換代碼

應用的基本框架搭建好了,咱們就來看看 showdown 這個 JavaScript 庫,咱們要用此庫把 Markdown 轉換爲 HTML。showdown 是用 JavaScript語言實現的,支持 Markdown 和 HTML 之間的雙向轉換。

用 Postman 測試

(高清大圖)

用 npm 安裝 showdown

$ npm install showdown
複製代碼

添加所需的 showdown 代碼後,咱們的代碼應該是這樣的:

const express        = require("express");
const bodyParser = require('body-parser');
const showdown   = require('showdown');
    
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
 
converter = new showdown.Converter();

app.get('/', function(req, res){
    res.send('Hello World!');
});
 
app.post('/login', function(req, res) {
    res.send("Authenticated");
  },
);
 
app.post("/convert", function(req, res, next) {
    if(typeof req.body.content == 'undefined' || req.body.content == null) {
        res.json(["error", "No data found"]);
    } else {
        text = req.body.content;
        html = converter.makeHtml(text);
        res.json(["markdown", html]);
    }
});
 
app.listen(3000, function() {
 console.log("Server running on port 3000");
});
複製代碼

轉換格式的核心代碼在 /convert 端點中,以下所示。這段代碼會把你上傳的 Markdown 文本轉換爲 HTML 版本,並返回 JSON 格式的結果。

...
} else {
        text = req.body.content;
        html = converter.makeHtml(text);
        res.json(["markdown", html]);
    }
複製代碼

converter.makeHtml(text) 就是負責轉換的方法。用 setOption 方法能夠對轉換過程進行各類配置:

converter.setOption('optionKey', 'value');
複製代碼

例如,能夠配置成自動插入特定的 URL 而不用任何標記。

converter.setOption('simplifiedAutoLink', 'true');
複製代碼

在 Postman 的例子中,若是咱們把 simplifiedAutoLink 的值配置爲 true,傳一個簡單的字符串(例如 Google home http://www.google.com/)時就會返回以下結果:

<p>Google home <a href="http://www.google.com/">http://www.google.com/</a></p>
複製代碼

不然,要實現相同效果,咱們必需要添加標記信息才行:

Google home <http://www.google.com/>
複製代碼

還有不少配置項能夠控制 Markdown 的轉換過程。你能夠在這裏找到完整的配置項列表。

如今,咱們實現了一個能將 Markdown 轉爲 HTML 的「轉換器」端點。讓咱們繼續深刻來添加驗證功能吧。

第四階段:用 Passport 實現接口驗證功能

不給接口添加恰當的驗證機制就把它扔出去給別人使用,就是在鼓勵使用者無限制地使用你的接口。這會招致某些無恥之徒濫用接口,蜂擁而至的請求會拖垮你的服務器。爲了不這樣的局面,咱們必須給接口添加恰當的驗證機制。

咱們將用 Passport 包來實現驗證機制。正如以前用到的 body-parser 中間件同樣,Passport 是一個基於 Node.js 的驗證中間件。使用它的緣由在於,它支持各類驗證機制(用戶名和密碼驗證、Facebook 帳號驗證、Twitter 帳號驗證等等),這樣咱們能夠靈活選擇驗證方式。添加 Passport 中間件很簡單,無需更改過多代碼。

用 npm 安裝 Passport:

$ npm install passport
複製代碼

咱們還要使用 local 策略來進行驗證,稍後我會詳細說明。所以要把 passport-local 也安裝上。

$ npm install passport-local
複製代碼

你還須要編碼/解碼模塊 JWT(JSON Web Token):

$ npm install jwt-simple
複製代碼

Passport 中的策略

Passport 中間件使用策略的概念來驗證請求。這裏所謂的策略就是一系列方法,它們幫你驗證各類請求,從簡單的用戶名密碼驗證,到開放受權驗證(Facebook 或 Twitter 帳號驗證),再到 OpenID 驗證,皆可勝任。一個應用所使用的驗證策略須要預先配置才能去驗證請求。

在咱們本身的應用中,咱們會用個簡單的用戶名密碼驗證方案,這樣便於理解和編碼。目前,Passport 支持超過 300 種驗證策略。

雖然 Passport 的設計很複雜,但實際使用卻很簡單。下面的例子就展現了 /convert 端點如何添加驗證機制。如你所見,垂手可得。

app.post("/convert", 
         passport.authenticate('local',{ session: false, failWithError: true }), 
         function(req, res, next) {
        // 若此函數被調用,說明驗證成功。
        // 請求內容爲空與否。
        if(typeof req.body.content == 'undefined' || req.body.content == null) {
            res.json(["error", "No data found"]);
        } else {
            text = req.body.content;
            html = converter.makeHtml(text);
            res.json(["markdown", html]);
        }}, 
        // 驗證失敗,返回 「Unauthorized」 字樣
        function(err, req, res, next) {
            return res.status(401).send({ success: false, message: err })
        });
複製代碼

如今,除了要轉換的 Markdown 字符串,咱們還要發送用戶名和密碼,與應用的用戶名密碼比對驗證。由於咱們使用的是本地驗證策略,驗證憑證就會存儲在代碼自己中。

可能這樣的驗證手段看起來太簡陋了,但對於一個 demo 級別的應用來講已經足夠。簡單的例子也有助於咱們理解驗證過程。順便說一句,有種常見的安全措施是把憑證存到環境變量中。固然,不少人對這種方式不覺得然,但我以爲這是個相對安全的方法。

驗證功能的完整示例以下:

const express = require("express");
const showdown  = require('showdown');
const bodyParser = require('body-parser');
const passport = require('passport');
const jwt = require('jwt-simple');
const LocalStrategy = require('passport-local').Strategy;
 
    
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
 
converter = new showdown.Converter();
 
const ADMIN = 'admin';
const ADMIN_PASSWORD = 'smagazine';
const SECRET = 'secret#4456';
 
passport.use(new LocalStrategy(function(username, password, done) {
  if (username === ADMIN && password === ADMIN_PASSWORD) {
    done(null, jwt.encode({ username }, SECRET));
    return;
  }
  done(null, false);
}));
 
app.get('/', function(req, res){
    res.send('Hello World!');
});
 
 
app.post('/login', passport.authenticate('local',{ session: false }),
                function(req, res) {
                // 若此函數被調用,說明驗證成功。
                // 返回 「Authenticated」 字樣。
                res.send("Authenticated");
  });
  
 
app.post("/convert", 
         passport.authenticate('local',{ session: false, failWithError: true }), 
         function(req, res, next) {
        // 若此函數被調用,說明驗證成功。
        // 請求內容爲空與否。
        if(typeof req.body.content == 'undefined' || req.body.content == null) {
            res.json(["error", "No data found"]);
        } else {
            text = req.body.content;
            html = converter.makeHtml(text);
            res.json(["markdown", html]);
        }}, 
        // 驗證失敗,返回 「Unauthorized」 字樣
        function(err, req, res, next) {
            return res.status(401).send({ success: false, message: err })
        });
 
 
app.listen(3000, function() {
 console.log("Server running on port 3000");
});
複製代碼

一個帶驗證的 Postman 會話以下所示:

用 Postman 測試最終應用

用 Postman 測試最終應用(高清大圖

在此可見,咱們上傳了一段 Markdown 語法的文本,而後獲得了通過正確轉換的 HTML 版本的結果。咱們只是測試了一行文本,但這個接口是有轉換大段文本的能力的。

這就是咱們這次對 Node.js 和 Express 的淺嘗 —— 搭建一個接口端點。構建接口是一個複雜的課題,在你想構建一個接口的時候,有些細節你應該清楚,但時間有限,很抱歉不能在本文中展開了,但可能會在後續文章中詳細探討。

在其餘應用中訪問咱們的接口

既然已經搭建好了接口,那咱們就能夠寫一個基於 Node.js 的小腳原本證實接口可用。在本例中,咱們須要安裝 request 包以便於發送 HTTP 請求。(極可能你已經安裝過了)

$ npm install request --save
複製代碼

下面所示代碼向咱們的接口發送了一個請求,並獲得了響應。如你所見,request 包大大簡化了步驟。待轉換的 Markdown 文本存放於 textToConvert 變量中。

在運行下列腳本以前,你要確保接口應用已經處於運行狀態。你須要在另外的命令窗口中運行腳本。

注意:在變量 textToConvert 中,咱們使用了 「 ` 」 符號來包裹多行 JavaScript 代碼,它不是單引號哦。

var Request = require("request");
 
// Markdown 文本的開頭
var textToConvert = `Heading ======= ## Sub-heading Paragraphs are separated by a blank line. Two spaces at the end of a line produces a line break. Text attributes _italic_, **bold**, 'monospace'. A [link](http://example.com). Horizontal rule:`;
 
// Markdown 文本的結尾
                    
Request.post({
    "headers": { "content-type": "application/json" },
    "url": "http://localhost:3000/convert",
    "body": JSON.stringify({
        "content": textToConvert,
        "username": "admin",
        "password": "smagazine"
    })
}, function(error, response, body){
    // 鏈接失敗時,退出。
    if(error) {
        return console.log(error);
    }
    // 顯示轉換後的文本
    console.dir(JSON.parse(body));
});
複製代碼

當發送 POST 請求到接口時,咱們須要提供要轉換的 Markdown 文本和身份憑證。若是憑證錯誤,咱們會收到錯誤提示信息。

{
  success: false,
  message: {
    name: 'AuthenticationError',
    message: 'Unauthorized',
    status: 401
  }
}
複製代碼

對於一個驗證經過的請求,上述 Markdown 樣例會被轉換爲以下格式:

[ 'markdown',
  `<h1 id="heading">Heading</h1>
  <h2 id="subheading">Sub-heading</h2>
  <p>Paragraphs are separated by a blank line.</p>
  <p>Two spaces at the end of a line<br />
  produces a line break.</p>
  <p>Text attributes <em>italic</em>, 
  <strong>bold</strong>, 'monospace'.
  A <a href="http://example.com">link</a>.
  Horizontal rule:</p>` ]
複製代碼

在例子中咱們刻意寫了一段 Markdown 文本,實際狀況中的文本可能來自文件、web 表單等多種來源。但請求過程都是同樣的。

注意:當咱們使用 application/json 格式發送請求時,咱們須要用 JSON 格式解析響應體,故而要調用 JSON.stringify 函數。如你所見,測試或者接口應用僅需一個小例子,在此不贅述。

總結

在本文中,咱們以學習使用 Node.js 和 Express 框架搭建接口爲目的組織了一次教程。與其漫無目的地作一些沒意思的應用,不如搭建一個把 Markdown 轉換爲 HTML 的接口,這纔算是有用的實踐。經過整個過程的實踐,咱們學會了給接口端點添加驗證機制,還學會了用 Postman 測試應用的幾種方式。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索