• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Express, jako hosting strony internetowej z odświeżaniem danych bez przeładowania

VPS Starter Arubacloud
+1 głos
399 wizyt
pytanie zadane 24 lutego 2021 w JavaScript przez Oskar Szkurłat Bywalec (2,780 p.)

Cześć, pracuję nad komunikacją i serwerem i chciałem się spróbować z nową dla mnie biblioteką Express. Klucz w tym, że potrzebuję hostować stronę, która będzie odbierać dane z aplikacji i je przetwarzać. Oraz konieczna jest odpowiedź ze strony do aplikacji.
- Tak więc przygotowałem sobie już stronę, jej serwer, silnik renderingu (tu hbs).
- Udało mi się wysłać dane z serwera za pomocą przycisku do aplikacji (metodą post), chociaż jest to wywoływane przez operatora, a docelowo będę potrzebował aplikacją (po stronie strony www) odpowiednio uwarunkować. Zakładam, że wystarczy wtedy zrobić odpowiednie przekierunkowanie z poziomu js strony na np. '/akcja'.
- Dane wysyłane na serwer też niby działają, ale tu pojawia się pytanie, wykorzystałem metodę również post, jednak, żeby wyświetlić dane aktualnie wykorzystuje res.render('index', data), co stanowi problem, bo strona odświeżana jest gubiąc informacje o poprzednich danych (po prostu jest reloadowana). Czy jest jakaś metoda transmisji danych bez ponownego renderowania całej strony, tak aby tylko zmieniały się parametry zmiennych zdefiniowanych (tu np.{{test}})?
Oto aktualna wersja skrócona mojego kodu:
 

//___________ Libraries ___________
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const path = require('path')
//___________ Configuration ___________
const PORT = process.env.PORT || 8080
const PATH = __dirname + '/views'
app.set('views', PATH);
app.set('view engine', 'hbs')
app.use(express.static(path.join(__dirname, 'public')));
//___________ My files ___________
const routes = require('./routes/index')
//___________ Parsers ___________
app.use(bodyParser.json())
app.use(bodyParser.raw());
app.use(bodyParser.urlencoded({ extended: true }));
//___________ Routes ___________
app.use('/', routes)

app.listen(PORT)
const express = require('express')
const router = express.Router()

const PagesController = require('../controllers/PagesController');
const ScannerController = require('../controllers/ScannerController');

router.get('/', PagesController.home);
router.post('/ref', ScannerController.set);
router.post('/feedback', ScannerController.get);
module.exports = router
var data = { test: { dist: 0, angle: 0 } }
function get(req, res) {
    console.log(req.body.upvote)
    res.redirect('/')
}
function set(req, res) {
    let ggg = data
    res.emit(ggg);
    res.render('index', ggg);
}

module.exports = {
    set: set,
    get: get,
    data: data
}

Jak można zauważyć, ja przygotowuje sobie dane w obiekcie data, a potem na żądanie wysyłam je do serwera.

function home (req, res) { res.render('index') }
module.exports = { home: home }

Wewnątrz ciała strony mam na chwilę obecną testowe przyciski do odbioru i transmisji danych oraz dwa div'y ze zmiennymi.

<form action="/feedback" method="POST">
            <input type="submit" name="upvote" value="post feedback" />
        </form>
        <form action="/ref" method="post">
            <input type="submit" name="upvote" value="POST" />
        </form>
<div> {{test.dist}} </div>
<div> {{test.angle}} </div>

Czy da się w jakiś sposób wyświetlać i aktualizować zmienne na stronie bez jej przeładowywania, tak aby np. móc sobie je dodawać do tablicy, bez utraty poprzednich. Czy da się to rozwiązać inaczej, niż bazą danych (np. moongose), zapisem do pliku (np. csv), bądź socket.io? A może znacie lepsze rozwiązanie, niż te co przedstawiłem?

Z góry dziękuję.

1 odpowiedź

+1 głos
odpowiedź 24 lutego 2021 przez ScriptyChris Mędrzec (190,190 p.)
wybrane 24 lutego 2021 przez Oskar Szkurłat
 
Najlepsza

Czy da się w jakiś sposób wyświetlać i aktualizować zmienne na stronie bez jej przeładowywania, tak aby np. móc sobie je dodawać do tablicy, bez utraty poprzednich.

Tak, użyj Ajax. Wystaw w Express-ie endpoint na metodę GET, wyślij pod niego request z frontu i niech serwer odeśle tylko dane - nie używaj wtedy metody render, tylko odeślij dane np. JSON-em. Możesz też dane wysłać z serwera do klienta za pomocą Server Sent Events.

Jeśli te dane nie będą zmieniać się w czasie, to możesz przechować je w Local Storage i wtedy po załadowaniu strony z URL'a, pod którym serwer zwraca dane przy okazji renderingu, front sobie je zapisze, a przy każdym odświeżeniu odczyta ze Storage. W takim przypadku nie potrzeba Ajax'a, ale dane będą świeże tylko w momencie renderowania strony - chyba, że zaimplementujesz mechanizm sprawdzania świeżości danych i ewentualnego dociągania nowych w razie aktualizacji.

komentarz 24 lutego 2021 przez Oskar Szkurłat Bywalec (2,780 p.)

W jaki sposób json miałby być przenoszony, jako emit z odpowiedzi, czy zapisany do zewnętrznego pliku, który będzie czytany przez AJAX? Czyli przykładowo zapisać, jako plik json o zawartości {zasieg: 100} z aplikacji:

app.get('/ref', function (req, res) {
    let data = {zasieg: 100}
    res.emit(data) //json ma być wysłany?
    fs.writeFileSync('/json/data.json', JSON.stringify(data)) //czy zapisany, jako plik i odczytany?
})

A potem po stronie strony odczytać z pliku z jQuery - Ajax:

$.getJSON( "/json/data.json", function( json ) {
  console.log( "JSON Data: " + json.zasieg );
 });

Na takiej zasadzie? Drugi pomysł niestety w tym rozwiązaniu odpada, ale dziękuję za informację.

2
komentarz 24 lutego 2021 przez JAKUBW Nałogowiec (33,470 p.)

Nie używaj jquery, użyj fetcha:

fetch('/twoj-jakis-link').then(e => e.json()).then(obj => console.log('Mój obiekt', obj));

Fetcha dodatkowo możesz użyć z await/async, jest wygodniejszy wtedy.

Po stronie serwera to tak obsługujesz:

app.get('/twoj-jakis-link', (req, res) => {
    const data = {zasieg: 100}
    res.send(data)
})

 

komentarz 24 lutego 2021 przez Oskar Szkurłat Bywalec (2,780 p.)

Zdecydowanie lepszy i praktyczniejszy zapis :) działa dzięki.

Jeszcze jedno pytanie mi się nasunęło, istnieje jakiś sposób, żeby z poziomu node.js wystawiać requesty na serwer? tzn. żeby aplikacja mogła 'zasymulować' np. '/twoj-jakis-link'.
Znalazłem postman-request, w nim za pomocą form można byłoby ustawić np. http://moje_ip/ref z pustym obiektem formy i aplikacja zareagowałaby na żądanie?

request.post('http://service.com/upload').form({key:'value'})

Czy istnieje istnieje jakiś rozsądniejszy sposób?

komentarz 24 lutego 2021 przez ScriptyChris Mędrzec (190,190 p.)

istnieje jakiś sposób, żeby z poziomu node.js wystawiać requesty na serwer?

Jeśli przez "wystawiać" masz na myśli wysyłać, to tak, można z poziomu Node wysyłać requesty natywnie lub przy pomocy np. biblioteki symulującej wspomniany wyżej przeglądarkowy fetch.

Znalazłem postman-request, w nim za pomocą form można byłoby ustawić np. http://moje_ip/ref z pustym obiektem formy i aplikacja zareagowałaby na żądanie?

Jeśli wysłałbyś to na URL, pod którym serwer obsługuje zapytania POST, to tak, możesz w ten sposób wysłać dane formularza. Tylko dlaczego miałbyś wysyłać pusty formularz?

Czy istnieje istnieje jakiś rozsądniejszy sposób?

Nie bardzo rozumiem co chcesz zrobić i o jakiej symulacji mówisz?

komentarz 24 lutego 2021 przez Oskar Szkurłat Bywalec (2,780 p.)
edycja 24 lutego 2021 przez Oskar Szkurłat
Teraz jak rozumiem serwer z każdym fetchem aktualizuje wartość jsona zwracanego na zadanym routcie. Czyli np. jak zrobię setInterval na stronie, a wewnątrz niego fetch, to co np. sekundę będę miał aktualizowane dane, które np. mogę wyplotować.
Spytałem o wysyłanie z poziomu node.js ze względu na to, że mam asynchroniczne funkcje (reszta programu) i przydałaby się informacja od serwera do strony "zaktualizuj dane na routerze '/ref'" w zadanym przez mój program momencie, tak aby móc zsynchronizować wyświetlanie na stronie z aplikacją (moment przychodzenia danych). Bo w tym momencie, jak np. będę miał fetch co 10ms, to musiałbym zabezpieczyć przed powielaniem danych, a większy czas wiązałby się z gubieniem niektórych danych (przy zmianie ich wartości szybszej, niż wywołanie fetcha).
//Edit: Jedyne co mi przychodzi póki co do głowy to zrobienie fetcha na routerze nasłuchu i ustawić go w interwale np. 1 ms i na podstawie wartości sczytanej z jsona wywoływać odpowiednie fetche ;)
1
komentarz 24 lutego 2021 przez ScriptyChris Mędrzec (190,190 p.)

Teraz jak rozumiem serwer z każdym fetchem aktualizuje wartość jsona zwracanego na zadanym routcie. Czyli np. jak zrobię setInterval na stronie, a wewnątrz niego fetch, to co np. sekundę będę miał aktualizowane dane, które np. mogę wyplotować.

Świeżość danych będzie zależeć od implementacji na serwerze. Jeśli z Node będziesz odsyłać te same dane, to nie ma różnicy ile razy wyślesz request z frontu, bo zawsze otrzymasz to samo. Ale, jeśli na serwerze na każdy przysłany request wykonasz jakąś logikę, której wynikiem będą nowe (zaktualizowane) dane i to odeślesz na front, to wtedy faktycznie front otrzyma świeże dane w odpowiedzi na wysłane requesty.

przydałaby się informacja od serwera do strony "zaktualizuj dane na routerze '/ref'" w zadanym przez mój program momencie

Ale to serwer obsługuje routingi - front zazwyczaj prosi o konkretną stronę do pokazania i nie interesuje go, co się dzieje na innych stronach w danym momencie - i to on powinien pilnować aktualności danych. Jeśli serwer ma w wybranym przez niego momencie powiadamiać o czymś frontend, to tak jak wspomniałem, użyj Server Sent Events lub choćby zastosuj technikę Long Polling'u przy Ajax'ie (ewentualnie WebSocket, ale jeśli nie zależy Ci szczególnie na komunikacji dwustronnej, to moim zdaniem nie ma to sensu dla tak prostego przypadku).

Bo w tym momencie, jak np. będę miał fetch co 10ms, to musiałbym zabezpieczyć przed powielaniem danych, a większy czas wiązałby się z gubieniem niektórych danych (przy zmianie ich wartości szybszej, niż wywołanie fetcha).

Taki scenariusz - gdy z frontu potrzebujesz cyklicznie odpytywać serwer o świeże dane - nadaje się właśnie pod użycie wspomnianych Long Polling lub SSE.

komentarz 24 lutego 2021 przez ScriptyChris Mędrzec (190,190 p.)

//Edit: Jedyne co mi przychodzi póki co do głowy to zrobienie fetcha na routerze nasłuchu i ustawić go w interwale np. 1 ms i na podstawie wartości sczytanej z jsona wywoływać odpowiednie fetche ;)

Chodzi o router na froncie (to jest apka SPA?), czy na backendzie? Takie brute force'owe sprawdzanie za pomocą interwału to ostateczność. Lepiej posłużyć się API danej biblioteki/frameworka (zazwyczaj ich routery posiadają hooki, do których można się wpiąć i nasłuchiwać na eventy nawigacji), albo natywnymi eventami runtime'u JavaScriptu żeby powiadamiać o wystąpieniu danej sytuacji (np. nawigacji).

Podobne pytania

+2 głosów
2 odpowiedzi 288 wizyt
0 głosów
1 odpowiedź 174 wizyt
pytanie zadane 14 września 2019 w JavaScript przez Louel Nowicjusz (140 p.)
0 głosów
2 odpowiedzi 460 wizyt
pytanie zadane 6 czerwca 2016 w PHP przez Alterwar Dyskutant (7,650 p.)

92,451 zapytań

141,261 odpowiedzi

319,073 komentarzy

61,853 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...