Предисловие: О http-сервере
Должны быть друзья, которые знают или использовали егоhttp-server
,http-server
Это http-сервер командной строки в среде node, вот ссылка на официальный сайт npm.Уууу, эта лошадь plus.com/package/red-glowing…,
Его использование можно найти на официальном сайте npm:
То есть после установки npm введите команду в командной строкеhttp-server
Запустите сервер напрямую.В каталоге, где запущен сервер, по умолчанию будет найден общедоступный каталог статических ресурсов, и вы можете получить доступ к сайту статического каталога, посетив адрес по умолчанию 127.0.0.1:8080.
Очень прост в использовании и удобен, если мы хотим изменить порт, каталог по умолчанию или имя хоста и т. д., его можно настроить непосредственно в командной строке при запуске.
Конкретное использованиеcmd: http-server -p 3001
Тогда при запуске будет доступен порт 3001. Для других конфигураций, пожалуйста, обратитесь к официальному сайту npm за подробностями, поэтому я не буду здесь вдаваться в подробности. В этой статье в основном рассматривается реализация простого пакета http-server с помощью базового принципа http-server.После реализации вы также можете отправить его в npm, чтобы он стал вашей собственной работой.Давайте посмотрим.
регистр npm
Студенты, которые хотят знать о публикации npm, могут зарегистрировать свою учетную запись npm на официальном сайте npm.Обратите внимание, что адрес электронной почты должен быть подтвержден, иначе они не смогут публиковать свои собственные пакеты.
Некоторые из лучших вещей, которые нужно знать заранее, прежде чем начинать проект
- среда nodejs
- fs, включая чтение файлов, чтение и запись потоков и т. д.
- асинхронно, обещаю
- http знания
- шаблонизатор ejs
Строительство одного проекта
package.json
Первое, что нужно сделать, это установить среду узла, потому что наш проект — это инструмент http, основанный на nodejs. После создания папки проекта можно использовать npm или yarn для ее инициализации.Создать файл package.json проекта.Следовать подсказкам инструмента управления пакетами в процессе настройки.При вводе имени можно использовать имя пакет, который вы хотите опубликовать; ввод автора Имя пользователя, которое вы зарегистрировали на официальном сайте npm, по умолчанию версия 1.0.0 Моя конфигурация pachage.json выглядит следующим образом
Здесь мы настраиваем bin для запуска пользовательского имени командной строки: «bin/www.js», в качестве нашего файла конфигурации запуска командной строки.
main: index.js — наш основной логический скрипт
автор — имя автора, здесь вы можете использовать имя пользователя официального сайта npm, чтобы сохранить то же самое
структура папок
Рекомендуется настроить это
Во-первых, это папка bin, а под ней находится www.js, здесь мы используем его для настройки инструмента командной строки, который также является ключом к пакету запуска.
node_modules генерируется после установки зависимостей, не обращайте внимания
public - это статический каталог ресурсов, к которому мы хотим, чтобы пользователи имели доступ, вы можете поместить некоторые папки и файлы по желанию
src — это наш основной js и конфигурация
src/template.html — это отображаемый интерфейс, потому что мы хотим создать статический ресурсный сайт, пользователям нужен доступ к странице, и они могут нажимать на каталоги или файлы и выполнять другие операции.
Два основных кода
1. src/config.js
Сначала мы создаем config.js, элемент конфигурации по умолчанию.
module.exports = {
port: 8080, // 默认端口
host: 'localhost', // 默认主机名
dir: process.cwd() // 默认读取目录
}
Мы экспортируем номер порта по умолчанию, имя хоста по умолчанию и каталог файлов по умолчанию,
Где process.cwd() — это текущий рабочий каталог процесса чтения, где вы его запускаете и какой каталог вы читаете
2. src/template.html
Как упоминалось выше, для отображения каталога используется файл template.html Здесь мы используем механизм шаблонов ejs и рендеринг на стороне сервера для отображения. здесь естьВведениеВы можете легко понять написание.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h2><%=name%></h2>
<%arr.forEach(item=>{%>
<li><a href="<%=item.href%>"><%=item.name%></a></li>
<%})%>
</body>
</html>
h2
В ярлыке показываем текущий путьli
Это файловая структура каталогов, по которой можно щелкнуть, чтобы войти в файл или папку; видно, что мы хотим вывести на эту страницу два данных name и arr, и как отобразить шаблон будет подробно описано в ядро JS.
3. src/index.js
Вот наш основной логический скрипт, в этот js будет инкапсулирован класс Server для запуска сервера в www.js
Краткая архитектура:
Модули, которые мы представляем, в основном включают:
- http http модуль
- util util tool module, в основном с использованием метода обещания
- модуль url url может легко получить путь
- модуль сжатия файлов zlib для создания потоков преобразования gzip или deflate
- модуль файловой системы fs
- конкатенация путей пути
- обработка пути строки запроса
- шаблонизатор ejs
- модуль chalk chalk может добавлять цвет к выходному тексту командной строки
- mime получить тип файла
- модуль отладки отладки
- config Файл конфигурации, который мы написали сами
Давайте начнем создавать класс Server для обработки различных ситуаций в запросе и возврата различного содержимого.
① Строительный сервер
class Server {
constructor(command) {
this.config = {...config,...command} // config和命令行的内容展示
this.template = template;
}
}
② Основной метод обработки запроса ※
class Server {
...
async handleRequest(req, res) {
let { dir } = this.config; // 需要将请求的路径和dir拼接在一起
//如 http://localhost:8080/index.html
let { pathname } = url.parse(req.url);
// 如果独到的是网站小图标,就直接输出
if (pathname === '/favicon.ico') return res.end();
pathname = decodeURIComponent(pathname); // 对文件夹名称进行转码处理
// p是决定文件路径
let p = path.join(dir, pathname);
try {
// 判断当前路径是文件 还是文件夹
let statObj = await stat(p);
if (statObj.isDirectory()) {
// 读取当前访问的目录下的所有内容 readdir 数组 把数组渲染回页面
res.setHeader('Content-Type', 'text/html;charset=utf8')
let dirs = await readdir(p);
dirs = dirs.map(item=>({
name:item,
// 因为点击第二层时 需要带上第一层的路径,所有拼接上就ok了
href:path.join(pathname,item)
}))
// 渲染template.html中需要填充的内容,name是当前文件目录,arr为当前文件夹下的目录数组
let str = ejs.render(this.template, {
name: `Index of ${pathname}`,
arr: dirs
});
// 响应中返回填充内容
res.end(str);
} else {
// 如果不是文件夹,则直接输出文件内容
this.sendFile(req, res, statObj, p);
}
} catch (e) {
debug(e); // 发送错误
this.sendError(req, res);
}
}
...
}
③ Обрабатывать пользовательский кеш
Он используется, чтобы сообщить серверу, есть ли кеш на этот раз.Если это файл, который был закеширован клиентом браузера, просто прочитайте кеш напрямую, чтобы оптимизировать производительность.
class Server {
...
cache(req, res, statObj, p ) {
// 设置缓存头
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Expires', new Date(Date.now() + 10 * 1000).getTime());
// 设置etag和上次最新修改时间
let eTag = statObj.ctime.getTime() + '-' + statObj.size;
let lastModified = statObj.ctime.getTime();
// 传给客户端
res.setHeader('Etag', eTag);
res.setHeader('Last-Modified', lastModified);
// 客户端把上次设置的带过来
let ifNoneMatch = req.headers['if-none-match'];
let ifModifiedSince = req.headers['if-modified-since'];
// 其中任意一个不生效缓存就不生效
if (eTag !== ifNoneMatch && lastModified !== ifModifiedSince) {
return false;
}
return true;
}
...
}
④ Сжимать ли
Возврат сжатых файлов, оптимизация скорости доступа
class Server {
...
// 是否压缩
gzip(req, res, statObj, p) {
// 判断请求头是否设置了接收编码
let encoding = req.headers['accept-encoding'];
// 如果有则判断是否有gzip或者deflate
if (encoding) {
// gzip
if (encoding.match(/\bgzip\b/)) {
res.setHeader('Content-Encoding', 'gzip');
return zlib.createGzip();
}
// deflate
if (encoding.match(/\bdeflate\b/)) {
res.setHeader('Content-Encoding', 'deflate');
return zlib.createDeflate();
}
return false;
}
else {
return false;
}
}
...
}
⑤ Определите, есть ли запрос диапазона
Определить, является ли заголовок запроса
class Server {
...
range(req, res, statObj, p) {
let range = req.headers['range'];
// 有范围请求时返回读流,断点续传
if (range) {
let [, start, end] = range.match(/bytes=(\d*)-(\d*)/);
start = start ? Number(start) : 0;
end = end ? Number(end) : statObj.size - 1;
res.statusCode = 206;
res.setHeader('Content-Range', `bytes ${start}-${end}/${statObj.size - 1}`);
fs.createReadStream(p, {start, end}).pipe(res);
}
else {
return false;
}
}
...
}
⑥ Отправить файл
Метод отправки файла, то есть, если мы решим, что читаем файл, когда обрабатываем запрос, мы отправим файл для отображения пользователю.
class Server {
...
sendFile(req, res, statObj, p) {
if (this.cache(req, res, statObj, p)) {
res.statusCode = 304;
return res.end();
}
// 是范围请求就忽略
if (this.range(req, res, statObj, p)) return;
// 设置文件类型头,如果不设置,我们访问一个html文件可能会导致下载
res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');
// 如果是需要压缩则定义gzip转化流,讲文件压缩后输出
let transform = this.gzip(req, res, statObj, p);
if (transform) {
return fs.createReadStream(p).pipe(transform).pipe(res);
}
// 如果不是不需要压缩则直接返回文件
fs.createReadStream(p).pipe(res);
}
...
}
⑦ Ошибка обработки
Метод обработки ошибок в методе handleRequest,
class Server {
...
sendError(req, res){
// 返回的状态码设置为404
res.statusCode = 404;
// 页面返回文字
res.end(`404 Not Found`);
this.start();
}
...
}
⑧ Как начать
Метод создания сервера собственного модуля http, после успешного создания выводится интерфейс cmd для информирования хоста и порта
class Server {
...
start() {
let server = http.createServer(this.handleRequest.bind(this));
server.listen(this.config.port, this.config.host, ()=> {
console.log(`server start http://${this.config.host}:${chalk.green(this.config.port)}`);
});
}
...
}
На данный момент наш основной код написан, и некоторые ситуации, которые необходимо решать на стороне сервера, легко обрабатываются.Заинтересованные студенты могут дополнять и улучшать
Три скрипта выполнения bin/www.js
Команду вводим в командной строке, отладчик выполняет скрипт, и запускает сервер
Обратите внимание, что вы должны написать в начале www.js#! /usr/bin/env node
Скажите среде узла операционной системы, чтобы она выполнялась, ниже приводится содержимое www.js
#! /usr/bin/env node
let Server = require('../src/index.js'); // 导入Server
let commander = require('commander'); // 导入命令行模块
let {version} = require('../package.json'); // 读取package.json的版本
// 配置命令行
commander
.option('-p,--port <n>', 'config port') // 配置端口
.option('-o,--host [value]', 'config hostname') // 配置主机名
.option('-d,--dir [value]', 'config directory') // 配置访问目录
.version(version, '-v,--version').parse(process.argv); // 展示版本
let server = new Server(commander);
server.start(); // 启动
let config =require('../src/config');
commander = {...config, ...commander}
let os = require('os');
// 执行模块
let {exec} = require('child_process')
// 判断操作系统平台,win32是windows,执行访问程序,会自动弹出默认浏览器喔
if (os.platform() === 'win32') {
exec(`start http://${commander.host}:${commander.port}`);
}
else {
exec(`open http://${commander.host}:${commander.port}`);
}
Еще раз взгляните на нашу конфигурацию в package.json.
"bin": {
"zyx-http-server": "bin/www.js"
},
То есть наша команда запуска — zyx-http-server, а также мы можем дополнить другими командами по собственной конфигурации, напримерzyx-http-server -d public
, затем прочитайте public как корневой каталог статического ресурса
npm link
Помимо обработки зависимостей npm install в нашем пакете (ejs, chalk, debug и т.
Ссылка npm: связать пакет npm в любом месте с глобальной средой выполнения, чтобы пакет npm можно было запустить напрямую с помощью командной строки в любом месте.
четыре пробега
Запустите инструмент командной строки в папке выполнитьzyx-http-server -d public
, если нет проблем, мы выскочим
нажмите на папку
открыть файл
Исходный файл:Пока что мы реализовали легендарный статический сервер http-server, так как меня зовут zyx, я назвал его zyx-http-server
5 Опубликовать на официальном сайте npm
Учащиеся, которые не зарегистрировались, пожалуйста, перейдите первым, если вы видите этот шагофициальный сайт нпмЗарегистрируйте собственную учетную запись, и тогда мы сможем опубликовать в нашем собственном пакете.
Есть несколько вещей, которые нужно иметь в виду, прежде чем продолжить
- Переключите источник на узел npm.Если вы обычно используете cnpm или другие узлы, введите командную строку.
nrm use npm
переключать - Зарегистрированный адрес электронной почты в npm должен быть подтвержден.Официальный сайт отправит вам письмо с подтверждением, нажмите, чтобы подтвердить.Я столкнулся с ситуацией, когда оно было проверено, но не вступает в силу.В настоящее время вы можете перейти на официальный сайт, чтобы снова изменить адрес электронной почты. попробуйте
- Имя отправляемого пакета — это элемент конфигурации имени в package.json, Если оно не настроено в начале, вы можете написать собственное имя пакета, доступ к которому можно получить, посетивwww.npmjs.com/package/+ Имя вашего пакета, чтобы увидеть, занят ли он в npm.Если он занят, измените его.Если он занят, вы не можете его отправить.
npm login
нужно выполнить в командной строкеnpm login
Войдите в npm.Если вы не переключились на узел официального веб-сайта npm, cnpm также может войти с учетной записью npm, поэтому, пожалуйста, переключитесь на npm заранее.
npm publish
После успешного входа в систему вы можете выполнить
npm publish
команда, следующие подсказки будут отображаться, если выпуск будет успешным
Процесс обновления кода такой же, как и публикация, но вам нужно обновить номер версии в package.json. Это адрес моей посылки, если интересно, можете посмотретьzyx-http-server
использовать свой собственный пакет
все еще используюnpm i zyx-http-server -g
Чтобы установить этот пакет глобально или локально, попробуем:
может начать
Исправлена ошибка с папкой на китайском языке.
Перекодировать путь в методе handleRequest
Надеюсь, моя статья поможет вам~