Деплой / Docker тебе в помощь))
Я тебя уже понял что "дело не в ангуляре" и "не стэк а сео"... итд, но в данном случае я говорил о сложности софта, точнее о его относительной сложности. А насчёт сео и остального -- это понятно, думаю, без уточнений.---------- Добавлено 07.11.2019 в 11:30 ----------
Если тебе не нравятся более пороизводительные решения и "стэк" -- пиши на раритете и низкопроизводительных языках, я не против ))
Честно, ребзи, скажу что дорген это очень непростой софт, после которого покажутся поделками все API разных офисных контор, хотел закончить за день, а доделал за 10 дней, реально сложные задачи решаются, похож на небольшой поисковик. Node помогает компактностью кода, на фоне утсалости от печатания это даёт бонус...
По этому пункту серьезные сомнения, PHP даже с сокетами никогда по производительности не приблизится к NodeJs использующему V8(C++). Вобщем, вопрос касательно PHP и производительности на хайлоаде снят, причём снят давно и не мной. Что касается React/PHP чтобы сказать предметно именно по данному решению нужно проводить тесты.
Среда как раз непривычная, бибилотека интересная, опять же вопрос времени и накладных расходов на освоение. Вобщем мне не очень хочется разводить здесь Cassandra/Node c PHP/redis стэковые батлы, но скажу что сферы применения той же кассандры и редиса разные, это решения разных классов и сегментов, то же самое можно сказать по reactPHP и Node/ES7async/await / Предлагаю не тратить время, будет свободное, возможно проведу бэнчмарки, тогда можно будет предметно без кофейной гущи делать выводы по вопросу производительности.
Из последних бэнчмарков: это приведенный выше код для получеения контета при доработке и получении из него компанованного контента обогнал собранный аналог на PHP в... дело в том что я в данный момент не могу объктивно полностью оценть возможности предложенного решения поскольку тесты проводятся на локальном канале с "упором" в пропускную способность, что наблюдается на мониторе трафика, но... даже в этих условиях я обогнал PHP -вариант в 32 раза по скорости, то есть у NodeJs -варианта у меня страница с контентом отдаётся через 1.2 секунды после запроса, а у PHP -варианта за 32-40 секунд. Понимаю важны пруфы, но оформление бенчмарка как-нибудь отдельным матералом. Думаю если в любом направлении превосходить основную массу по скорости в 30-40 раз... это качественно другой уровень. Мне лично очень не нравятся колбэки и городить из них небоскрёбы, когда в ООП можно раскидать по классам и вызовам, но.. отчасти это моё нубовство в Node отчасти это просто непривычно... в целом результат мне нравится. Отдельным моментом планирую перевести работу с контентом в Go / C++ ноды, это ускорит работу софта ещё в разы. Пока такой итог, скоро мб выложу новый материал по достройке софта)
Node.SheduleAPI + redis
а за время на изучение рэббита выучить Cassandra
хотя ты мне подкинул задач . теперь ещё rebbitmq протестировать
Собственно REST API сервер под текст готов, примерно так выглядит ответ сервера на запрос по ключу
Так же отдельный микросервисы на изображения, на наполнение базы данных, загрузку на сервер. Примерно такие детали сейчас внутри разных современных модных сервисов, единственное чего нет токена и graphql-ля, но их дальше можно добавить, еще мб будет redis на раздачу заданий и выдачу ключевых фраз..
#Step 10 #add content api selector
Добавляем селектор, подключаем модули:
var express = require('express'); var app = express(); // HTTP header parser var bodyParser = require('body-parser'); // Create parser for HTTP POST application/x-www-form-urlencoded var urlencodedParser = bodyParser.urlencoded({extended: false}) //DEBUG / NOTIFY var debugLevel = 5 // Router GET app.get('/process_get', function (req, res) { // Prepare output formated in JSON response = { first_name: req.query.first_name, last_name: req.query.last_name }; console.log(response); res.end(JSON.stringify(response)); }) //searchengine : google //contenttype : text //searchrequest : keyword //useragent : chrome //library : axios app.get('/parser_api_get', function (req, res) { // Prepare output formated in JSON response = { searchengine : req.query.searchengine, //google content_type : req.query.content_type, //text / image search_request : req.query.search_request, //keyword library : req.query.library, //axios useragent : req.query.useragent, //chrome proxy_server : req.query.proxy_server, //chrome /** H1 in articles */ content_enable_h1_tag : req.query.content_enable_h1_tag, // boolean/blob 1 | 0 /** percent of paraphs prev begin by H1 tag 0-100(%) -- insert AFRER paragraph*/ content_h1_tag_freq_percent : req.query.content_h1_tag_freq_percent, // 0-100(%) /** source for create H1 text */ content_h1_tag_source : req.query.content_h1_tag_source, // one.random.keyword.from.keywords / extracted.h1.from.parsed.sites.by.selected.keyword /** H2 in articles */ content_enable_h2_tag : req.query.content_enable_h2_tag, // boolean/blob 1 | 0 /** percent of paraphs prev begin by H1 tag 0-100(%) -- insert AFRER paragraph*/ content_h2_tag_freq_percent : req.query.content_h2_tag_freq_percent, // 0-100(%) /** source for create H2 text */ content_h2_tag_source : req.query.content_h2_tag_source, // one.random.keyword.from.keywords / extracted.h2.from.parsed.sites.by.selected.keyword /** H3 in articles */ content_enable_h3_tag : req.query.content_enable_h3_tag, // boolean/blob 1 | 0 /** percent of paraphs prev begin by H3 tag 0-100(%) -- insert AFRER paragraph*/ content_h3_tag_freq_percent : req.query.content_h3_tag_freq_percent, // 0-100(%) /** source for create H3 text */ content_h3_tag_source : req.query.content_h3_tag_source, // one.random.keyword.from.keywords / extracted.h3.from.parsed.sites.by.selected.keyword /** IMG in articles -- insert BEFORE paragraph*/ content_enable_img_tag : req.query.content_enable_img_tag, // boolean/blob 1 | 0 /** percent of paraphs prev begin by IMG tag 0-100(%) -- insert BEFORE paragraph*/ content_img_tag_freq_percent : req.query.content_img_tag_freq_percent, // 0-100(%) /** source for create IMG in text */ content_img_source : req.query.content_img_source, // google.image.advanced.search / flickr / pinterest /** license type for IMG in text */ content_img_license_type : req.query.content_img_license_type, // cc / all /** width type for IMG in text */ content_img_width : req.query.content_img_width // 400 / 600 / 800 / 1000 /any }; //TO EXPORT //MAIN CONTENT API SWITCHER switch (response.searchengine) { case 'google' : if (debugLevel >= 1) console.log('go.google') //to export //CONTENT TYPE SWITCHER switch (response.content_type) { case 'text' : if (debugLevel >= 1) console.log('Content type is text') //to export //REQUEST OPTS if (response.search_request) { if (debugLevel >= 2) console.log('Search : ' + response.search_request) let search = response.search_request let crawlerLybrary if (response.library && (response.library == 'axios' || response.library == 'nightmare' ) ) { crawlerLybrary = response.library } else { crawlerLybrary = 'axios' } if (debugLevel >= 2) console.log('Crawl with lybrary : ' + crawlerLybrary) if (debugLevel >= 2) console.log('Search : ' + search) //to export //CRAWLER OPTS let useragent = '' let proxy_server = [] if (response.useragent) { useragent = response.useragent } if (response.proxy_server) { //add proxy_server.push || parse.str && push.elem proxy_server = response.proxy_server } if (debugLevel >= 3) console.log('Useragent : ' + useragent) if (debugLevel >= 3) console.log('Proxy server : ' + proxy_server) //useragent //proxy_server //end CRAWLER OPTS //REQUEST OPTS PIPE / MUX let requestOptions = [] requestOptions = { searchengine : 'google.com', search_request : search, useragent : useragent, proxy_server : proxy_server } if (debugLevel >= 1) console.log(requestOptions) //end REQUEST OPTS PIPE / MUX //MODULE SELECT switch (crawlerLybrary) { case 'axios' : const getPageGoogleSerp = require('../../se/getPageGoogleSerp') if (debugLevel >= 1) console.log('Get article with axios.module. With options :') if (debugLevel >= 1) console.log(requestOptions) getPageGoogleSerp(requestOptions) break case 'nightmare' : break } //end MODULE SELECT } else { if (debugLevel >= 1) console.log('Search request not set. Action ended.') } //end REQUEST OPTS break case 'image' : if (debugLevel >= 1) console.log('Content type is image') break default : if (debugLevel >= 1) console.log('Content type not set') break } //END CONTENT TYPE SWITCHER --> module.export / const contentTypeSwitcher = require(./contentTypeSwitcher) break case 'bing' : if (debugLevel >= 1) console.log('go.bing') //export //CONTENT TYPE SWITCHER break case 'yahoo' : if (debugLevel >= 1) console.log('go.yahoo') //export //CONTENT TYPE SWITCHER break case 'any' : if (debugLevel >= 1) console.log('go: google & bing & yahoo') //export //CONTENT TYPE SWITCHER break } console.log(response.searchengine); //console.log(response); res.end(JSON.stringify(response)); }) // localhost:3000/parser_api_get?searchengine=google&content_type=text&search_request=node+express+examples&library=axios&content_enable_h1_tag=0 // Router POST var server = app.listen(3000, function () { var host = server.address().address var port = server.address().port console.log("Content Server listening at http://%s:%s", host, port) })
node app.js
http://localhost:3000/parser_api_get?searchengine=google&content_type=text&search_request=node+express+examples&library=axios&content_enable_h1_tag=0
...
#Step 9 #content api
Конструируем API под получение и генерацию текста
app.get('/parser_api_get', function (req, res) { // Prepare output formated in JSON response = { searchengine : req.query.searchengine, //google content_type : req.query.content_type, //text search_request : req.query.search_request, //keyword library : req.query.library, //axios useragent : req.query.useragent, //chrome proxy_server : req.query.proxy_server, //chrome /** H1 in articles */ content_enable_h1_tag : req.query.content_enable_h1_tag, // boolean/blob 1 | 0 /** percent of paraphs prev begin by H1 tag 0-100(%) -- insert AFRER paragraph*/ content_h1_tag_freq_percent : req.query.content_h1_tag_freq_percent, // 0-100(%) /** source for create H1 text */ content_h1_tag_source : req.query.content_h1_tag_source, // one.random.keyword.from.keywords / extracted.h1.from.parsed.sites.by.selected.keyword /** H2 in articles */ content_enable_h2_tag : req.query.content_enable_h2_tag, // boolean/blob 1 | 0 /** percent of paraphs prev begin by H1 tag 0-100(%) -- insert AFRER paragraph*/ content_h2_tag_freq_percent : req.query.content_h2_tag_freq_percent, // 0-100(%) /** source for create H2 text */ content_h2_tag_source : req.query.content_h2_tag_source, // one.random.keyword.from.keywords / extracted.h2.from.parsed.sites.by.selected.keyword /** H3 in articles */ content_enable_h3_tag : req.query.content_enable_h3_tag, // boolean/blob 1 | 0 /** percent of paraphs prev begin by H3 tag 0-100(%) -- insert AFRER paragraph*/ content_h3_tag_freq_percent : req.query.content_h3_tag_freq_percent, // 0-100(%) /** source for create H3 text */ content_h3_tag_source : req.query.content_h3_tag_source, // one.random.keyword.from.keywords / extracted.h3.from.parsed.sites.by.selected.keyword /** IMG in articles -- insert BEFORE paragraph*/ content_enable_img_tag : req.query.content_enable_img_tag, // boolean/blob 1 | 0 /** percent of paraphs prev begin by IMG tag 0-100(%) -- insert BEFORE paragraph*/ content_img_tag_freq_percent : req.query.content_img_tag_freq_percent, // 0-100(%) /** source for create IMG in text */ content_img_source : req.query.content_img_source, // google.image.advanced.search / flickr / pinterest /** license type for IMG in text */ content_img_license_type : req.query.content_img_license_type, // cc / all /** width type for IMG in text */ content_img_width : req.query.content_img_width // 400 / 600 / 800 / 1000 /any }; console.log(response); res.end(JSON.stringify(response)); }) // localhost:3000/parser_api_get?searchengine=google&content_type=text&search_request=node+express+examples&library=axios&content_enable_h1_tag=0
Content Server listening at http://:::3000
{"searchengine":"google","content_type":"text","search_request":"node express examples","library":"axios","content_enable_h1_tag":"0"}
Для отладки до создания интерфейса под POST - реализация GET -запросом.
#Step8 #express REST API
Изначально идея заменить REST обработкой async/awayt без запросов к API несколько усложняла код, в целом это ни к чему, приост проивзодителньости... впринцие он врядли будет от такого решения. Потому:
npm i express body-parser
Express -- сервер на основе которого делают сайты и создают API для REST
body-parser -- парсер HTTP заголовков
можно ещё добавить GrapQL и jsonp / или добвить слой крипто но пока без них, хотя защитить API будет необходимо.
//app.js var express = require('express'); var app = express(); // HTTP header parser var bodyParser = require('body-parser'); // Create parser for HTTP POST application/x-www-form-urlencoded var urlencodedParser = bodyParser.urlencoded({extended: false}) // Router GET app.get('/process_get', function (req, res) { // Подготовка вывода в формате JSON response = { first_name: req.query.first_name, last_name: req.query.last_name }; console.log(response); res.end(JSON.stringify(response)); }) // Router POST var server = app.listen(3000, function () { var host = server.address().address var port = server.address().port console.log("Content Server listening at http://%s:%s", host, port) })
http://localhost:3000/process_get?first_name=john&last_name=doe
Отправляем - видим:
{"first_name":"john","last_name":"doe"}
Таким примерно образом будут реализованы запросы на получение контента, графики, на форматирование (возможно здесь придётся сделать вставку БД) и на загрузку контента в БД сайта и на сами действия и визуализации интерфейса, скрее всего разделять эти действия по отдельным API не будет иметь смысла для проекта такого масштаба.