Напишите веб-сервер, используя собственный API Node.js.

Node.js внешний интерфейс

Node.jsдаJavaScriptЯзык разрабатывался на основе, поэтому фронтенд-разработчикам надо родиться с небольшим. Обычно мы будем использовать его, чтобы сделатьCLI工具илиWeb服务器,ДелатьWeb服务器Есть также много зрелых фреймворков, таких какExpressа такжеKoa. ноExpressа такжеKoaотличноNode.jsРоднойAPIинкапсуляция, так по сути без фреймворка, только роднойAPIМы также можем написатьWeb服务器публично заявить. В этой статье речь пойдет не об использовании фреймворка, а только о нативномAPIкак написать одинWeb服务器. Потому что в моем плане я напишу позжеExpressа такжеKoaПарсинг исходного кода, все они реализованы с помощью нативного API. Так что эта статья на самом деле является предварительным знанием этих двух анализов исходного кода, которые могут помочь нам лучше понятьExpressа такжеKoaСмысл и исходный код этого фреймворка.В этой статье только объясняется, как использовать нативный API, код уродлив, пожалуйста, не имитируйте его в реальной работе!

Пример исполняемого кода из этой статьи был загружен на GitHub, вы можете снять его и поиграть:GitHub.com/Денис — см....

Hello World

Чтобы построить простойWeb服务器, используя роднойhttpмодуля достаточно, простойHello WorldДля программы достаточно нескольких строк кода:

const http = require('http')

const port = 3000

const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('Hello World')
})

server.listen(port, () => {
  console.log(`Server is running on http://127.0.0.1:${port}/`)
})

Этот пример очень прост, непосредственно используйтеhttp.createServerСоздал сервер, этот сервер не имеет логики, просто возвращается при доступеHello World. После создания сервера используйтеserver.listenдействующий3000Просто порт.

Этот пример действительно прост, но он, кажется, выводитHello WorldКроме того, он ничего не умеет, это далеко не то, чем мы обычно пользуемсяWeb服务器До этого еще далеко, в основном из-за следующих частей:

  1. не поддерживаетсяHTTPглаголы, такие какGET,POSTЖдать
  2. Маршрутизация не поддерживается
  3. Хостинг без статического ресурса
  4. Данные не могут быть сохранены

Первые три пункта являются однимWeb服务器Необходимые базовые функции, нужна ли четвертая точка, зависит от ситуации, в конце концов, есть многоNodeизWeb服务器Так же, как промежуточный слой, это все еще различные микросервисы, которые действительно имеют дело с базой данных для сохраняемости, но мы также должны знать, как делать сохраняемость.

Итак, давайте напишем действительно полезныйWeb服务器, то есть восполнить недостающие точки спереди.

Обработка маршрутизации и HTTP-команд

тот, что перед намиHello WorldЭто не совсем бесполезно, потому что местоположение кода все еще должно быть вhttp.createServerВнутри добавляем функцию роутинга внутри. Чтобы отличить его от следующих статических ресурсов, все запросы нашего API начинаются с/apiначало. Сопоставить маршруты несложно, проще всего напрямую использоватьifУсловное суждение подойдет. Чтобы получить адрес запроса, нам нужно использоватьurlмодуль для разбора переданного адреса. а такжеHttpглаголы могут использоваться напрямуюreq.methodполучать. такhttp.createServerТрансформация выглядит следующим образом:

const url = require('url');

const server = http.createServer((req, res) => {
  // 获取url的各个部分
  // url.parse可以将req.url解析成一个对象
  // 里面包含有pathname和querystring等
  const urlObject = url.parse(req.url);
  const { pathname } = urlObject;

  // api开头的是API请求
  if (pathname.startsWith('/api')) {
    // 再判断路由
    if (pathname === '/api/users') {
      // 获取HTTP动词
      const method = req.method;
      if (method === 'GET') {
        // 写一个假数据
        const resData = [
          {
            id: 1,
            name: '小明',
            age: 18
          },
          {
            id: 2,
            name: '小红',
            age: 19
          }
        ];
        res.setHeader('Content-Type', 'application/json')
        res.end(JSON.stringify(resData));
        return;
      }
    }
  }
});

теперь мы посещаем/api/usersВы можете получить список пользователей:

image-20201005214628113

Поддержка статических файлов

сказано вышеAPIзапрос/apiВ начале, то есть файлы, которые не начинаются с этого, можно рассматривать как статические файлы, и разные файлы имеют разныеContent-TypeВ этом примере мы поддерживаем только один..jpgБар. На самом деле это для насif (pathname.startsWith('/api'))добавить одинelseПросто сделай это. Для возврата статических файлов требуется:

  1. использоватьfsМодуль читает файл.
  2. Возвращает файл, если он отличается в зависимости от разных типов файлов.Content-Type.

так что мыelseЭто выглядит так:

// ... 省略前后代码 ...

else {
  // 使用path模块获取文件后缀名
  const extName = path.extname(pathname);

  if (extName === '.jpg') {
    // 使用fs模块读取文件
    fs.readFile(pathname, (err, data) => {
      res.setHeader('Content-Type', 'image/jpeg');
      res.write(data);
      res.end();
    })
  }
}

Затем мы помещаем изображение в каталог того же уровня, чтобы попробовать:

image-20201007092853547

сохранение данных

Существует несколько способов сохранения данных, как правило, они хранятся в базе данных, а в некоторых случаях и в файлах. Хранить базу хлопотнее, да и создавать и подключаться к базе тоже надо, тут у нас плохо.demo, здесь мы демонстрируем пример сохранения файла. в общемPOSTЗапрос используется для сохранения новых данных, мы добавляем базу передPOST /api/usersЧтобы добавить новый фрагмент данных, просто добавьтеif (method === 'GET')добавить один послеPOSTСуд сделает:

// ... 省略其他代码 ...

else if (method === 'POST') {
  // 注意数据传过来可能有多个chunk
  // 我们需要拼接这些chunk
  let postData = '';
  req.on('data', chunk => {
    postData = postData + chunk;
  })

  req.on('end', () => {
    // 数据传完后往db.txt插入内容
    fs.appendFile(path.join(__dirname, 'db.txt'), postData, () => {
      res.end(postData);  // 数据写完后将数据再次返回
    });
  })
}

Затем мы тестируем этоAPI:

image-20201007165330636

Зайди и посмотри, написано ли в файле:

image-20201007165506756

Суммировать

Здесь мы выполнили основную функциюweb服务器, код не сложный, но чтобы помочь нам понятьNode web服务器Принцип очень полезный. Но с приведенным выше кодом все еще есть большая проблема:код уродлив! Весь код написан кучей, иHTTP动词и сопоставление маршрутов все используетifУсловное суждение, если есть сотниAPI, с дюжиной или около того глаголов, и код — это катастрофа! Поэтому мы должны поставить路由处理,HTTP动词,静态文件,数据持久化Все эти функции извлекаются, что делает все приложение более элегантным и масштабируемым. ЭтоExpressа такжеKoaО значении этих фреймворков мы поговорим в следующей статьеExpressИсходный код, чтобы увидеть, как он решает эту проблему, нажмите на него и не теряйтесь~

Пример исполняемого кода из этой статьи был загружен на GitHub, вы можете снять его и поиграть:GitHub.com/Денис — см....

В конце статьи спасибо, что потратили свое драгоценное время на чтение этой статьи. Если эта статья немного поможет вам или вдохновит, пожалуйста, не скупитесь на лайки и звезды GitHub. Ваша поддержка является движущей силой для автор продолжать творить.

Добро пожаловать, чтобы обратить внимание на мой общедоступный номербольшой фронт атакиПолучите высококачественные оригиналы впервые~

Цикл статей "Передовые передовые знания":nuggets.capable/post/684490…

Адрес GitHub с исходным кодом из серии статей «Advanced Front-end Knowledge»:GitHub.com/Денис — см....