Funkcja na serwerze wywoływana przez klienta

Funkcja na serwerze wywoływana przez klienta
Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0

Cześć,
Buduję apkę na serwerze node.js i express i natrafiłem na ścianę. Stworzyłem funkcję zapisującą plik z zawartością pobierana przez API na swój serwer przy pomocy fs. Chciałbym ja teraz wywoływać przy pomocy buttona po stronie Klienta. Nie mogę umieścić funkcji w publicznym katalogu bo wtedy mam błąd CORS. Próbowałem wyeksportować funkcję przez module.exports ale umieszczając kod w szablonie Handlebars onclick = "{{ mojaFunkcja();" }} nie udaje sie tego wykonać (wartość onclick w wygenerowanym kodzie jest pusta). Próbowałem podzielić funkcję na zmienne pobierane z API oraz na funkcję zapisującą plik na serwer i umieściłem ją po stronie klienta ale tu mam kolejny problem bo tam nie mogę zaimportować fs przez import ani require - przeglądarka wywala błąd "require not defined" lub "crbug/1173575, non-JS module files deprecated."

w Javascripcie piszę się od kilku miesięcy a node.js od kilku dni. Co powinienem zrobić aby uruchomić moją funkcję z przycisku?

edytowany 1x, ostatnio: Riddle
FI
  • Rejestracja:ponad 13 lat
  • Ostatnio:18 dni
  • Postów:684
0

Nie wiem jaki wzorzec zastosowałeś, ale jeśli zrobisz to na MVC, to możesz utworzyć warstwę backendu oraz warstwę widoku (front) oraz zrobić komunikację między nimi poprzez express.json().
Jeśli natomiast łączysz Node.js z React.js, to w react nie ma "onclick", tylko raczej "onClick", czyli tak zwany event natywny.
Jednak podejrzewam, że nie jesteś jeszcze na etapie łączenia react.js z node.js, więc na początek poczytaj o Node.js MVC oraz o express.json(...)
Komentarz, po przeredagowanym poscie:
@Bart Eagle: Słusznie @szafran98 zauważył, bo źle powiedziałem. Możesz właśnie poczytać o "express.json(...)"
lub w ogóle o express. Możesz też poczytać o opcji "ejs", czyli rozwiązaniu w postaci renderowania w warstwie widoku.

edytowany 3x, ostatnio: finito
1programmer
Na jakiej zasadzie łączy się akcje na froncie z backiem przez JSONa?
marcyse
Łączysz się po API wystawionym i przesyłasz jsona dajmy na to z nazwą fukncji, na backendzie to przechwytujesz i wywołujesz odpowiednią funkcje. To troche bez sensu ale możliwe
1programmer
@marcyse: No to oczywiste, ale finito tak napisał, że można wywnioskować jakoby front i back działały jako jedna aplikacja i można było wywołać funkcję z backu na froncie. W sumie tak jak napisałeś, ale właśnie jest to raczej bez sensu.
FI
@szafran98: Sorry, to był taki nie poprawny skrót myślowy. Głównie sorry w kierunku autora wątku;-)) Zgadza się, chodziło mi o express.json(...).
1programmer
  • Rejestracja:prawie 5 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
  • Postów:525
0

Pokaż kod kolego, tą funkcję zapisującą plik.


Programować muszę, bo się uduszę
Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0

Kod całej działającej funkcji:

Kopiuj
function uploadJobticket() { 
    const OrderUrl = "ApiUrl + IdOrder + "/" + ApiKey;


    fetch(OrderUrl)
        .then(response => {
            if (response.ok) {
                console.log("Połączenie z OrderGroup Aktywne")
                
                return response.json();
            } else {
                return Promise.reject(`Http error: ${response.status}`);
            }
        })
        .then(response => {
            let Infos = response.result.orderRepresentationHeaders.length;
            let IdNumbers = new Array();
            for (let i=0; i < Infos; i++) {
                IdNumbers.push(response.result.orderRepresentationHeaders[i].id)
            }
            console.log("Numery ID :" + IdNumbers);
            console.log("Ilość zleceń: " + Infos);
            let orderNr = response.result.id;


            for (let b=0; b < Infos; b++) { 
        
                const IdOrder = IdNumbers[b];
                const url = ApiUrl2 + IdOrder + ApiKey;  
                
                fetch(url)
                    .then(res => {
                        if (res.ok) {
                            console.log("Połączenie z Order Aktywne")
                            return res.json()
                            
                        } else {
                            return Promise.reject(`Http error: ${res.status}`);
                        }
                    })
                .then(res => {
                           
                        let objectToSend = {};
                    
                        objectToSend.type = "jobticket";
                        const params = new Array();
                        objectToSend.params = params;
                    
                            let jobID = b + 1;
                            
                            let productName = res.result.productTitle.replace(/ /g,"_");
                            let NrOfFiles = res.result.orderFileRepresentations.length;
                            console.log("Ilość plików w zleceniu: " + NrOfFiles);

                            for ( let c=0; c < NrOfFiles; c++ ) {
 
                                try {
                                    let fileName = res.result.orderFileRepresentations[c].fileName;
                                    params.push("E:\\Dropbox\\2022\\" + orderNr + "\\" + orderNr + "-" + jobID + "\\" + fileName);
                                } catch (error) {
                                    console.log("Nie dodano plików do zamówienia")  
                                    //console.error(error);
                                }
                            }    
                            
                            let paramsLength = res.result.params.length;
                            
                            params.push("E:\\JSON_TEST\\PROFIL\\PREFLIGHT.kfpx");
                            params.push("--setvariable=nazwa_produktu:" + productName);
                            params.push("--setvariable=id:" + jobID);
                        
                       
                            for (let a=0; a < paramsLength; a++) {
                                let paramName = res.result.params[a].parameterTitle;
                                let newName = paramName.toString().replace(" [cm]", "").replace("  [cm]", "").replace(/ /g,"_").replace(/ą/g,"a").replace(/ę/g,"e").replace(/ó/g,"o").replace(/ś/g,"s").replace(/ł/g,"l").replace(/ż/g,"z").replace(/ź/g ,"z").replace(/ć/g ,"c").replace(/ń/g , "n");

                                let slash = "/";
                                let paramValue = res.result.params[a].value
                                let newValue = paramValue.toString().replace(/ /g,"_").replace(slash , "-").replace(/ą/g,"a").replace(/ę/g,"e").replace(/ó/g,"o").replace(/ś/g,"s").replace(/ł/g,"l").replace(/ż/g,"z").replace(/ź/g ,"z").replace(/ć/g ,"c").replace(/ń/g , "n");
                           
                                
                                console.log (newName + " : " +  newValue);
                                params.push("--setvariable=" + newName + ":" + newValue); 
                            }
                           
                            console.log(JSON.stringify(objectToSend));
                             
                            const jobticketName = orderNr + "-" + jobID + ".jobticket";
                            const path = "E:/JSON_TEST/IN/" + jobticketName;
        
                            fs.writeFile(path, JSON.stringify(objectToSend), function(err) {
                                if(err) {
                                    return console.log(err);
                                }
                            console.log("Plik " + jobticketName + " został zapisany")
                            });

                })
                .catch(error => {
                    console.error(error);
                });
            }   

        })
        .catch(error => {
                console.error(error);
        
             });
edytowany 1x, ostatnio: Bart Eagle
1programmer
  • Rejestracja:prawie 5 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
  • Postów:525
0

No to teraz ta funkcja działa na froncie i zapisujesz plik z poziomu aplikacji frontowej. Musisz napisać na backendzie endpointa, który przyjmie ten plik i tam za pomocą fs zapisze. Do wysłania pliku możesz wykorzystać API FormData i multer (https://www.npmjs.com/package/multer), albo masz w node wbudowane streamy (https://nodejs.dev/learn/nodejs-streams)

Dodatkowo mógłbyś rozbić tą funkcję na mniejsze bloki wykonujące stosowne zapytania, bo jest zdecydowanie za duża. Polecam też korzystanie z async/await, bo kod będzie czytelniejszy.


Programować muszę, bo się uduszę
edytowany 2x, ostatnio: 1programmer
Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0
szafran98 napisał(a):

No to teraz ta funkcja działa na froncie i zapisujesz plik z poziomu aplikacji frontowej. Musisz napisać na backendzie endpointa, który przyjmie ten plik i tam za pomocą fs zapisze. Do wysłania pliku możesz wykorzystać API FormData i multer (https://www.npmjs.com/package/multer), albo masz w node wbudowane streamy (https://nodejs.dev/learn/nodejs-streams)

Ta funkcja nie działa jeszcze na froncie, chodzi mi o to by w ogóle ją tam wywołać :)

1programmer
  • Rejestracja:prawie 5 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
  • Postów:525
0

No to musisz napisać endpointa na backendzie, który przy otrzymaniu requesta ją wywoła. Jeśli będziesz potrzebował, to możesz w nim przesłać dodatkowe dane z frontu. Po wywołaniu również możesz zwrócić odpowiedź na front.


Programować muszę, bo się uduszę
Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0
szafran98 napisał(a):

No to musisz napisać endpointa na backendzie, który przy otrzymaniu requesta ją wywoła. Jeśli będziesz potrzebował, to możesz w nim przesłać dodatkowe dane z frontu. Po wywołaniu również możesz zwrócić odpowiedź na front.

będę zbyt bezczelny jak cię poproszę o przykład?

Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0
szafran98 napisał(a):

No to musisz napisać endpointa na backendzie, który przy otrzymaniu requesta ją wywoła. Jeśli będziesz potrzebował, to możesz w nim przesłać dodatkowe dane z frontu. Po wywołaniu również możesz zwrócić odpowiedź na front.

o to coś takiego chodzi? https://bluegrid.io/how-to-setup-api-endpoint-for-a-simple-project-in-node-js/

marcyse
zobacz sobie jak niektórzy implementują swoje api restowe na githubie, to idealny sposób na poznanie dobrych praktyk, a i sam ogarniesz jak mniej więcej będzie działać to zapisywanie i obsługa błędów
1programmer
  • Rejestracja:prawie 5 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
  • Postów:525
0

Nie wiem w czym masz back i czy faktycznie już go masz. Jeśli nie to sprawdź bibliotekę express. W dokumentacji będziesz miał przykłady.


Programować muszę, bo się uduszę
Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0

Biblioteki już mam Mongose, Express i Handlebars. Dzięki, przynajmniej wiem czego szukać.

Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0

Dobra, w jedną stronę się udało wykonując prosty punkt końcowy:

Kopiuj
app.get('/api/jobtickets', (req, res) => res.json({
    "result": "ok",
    "job": uploadJobticket.waitForJob()
}))
Kopiuj
exports.order = (req, res) =>
    res.render('order', {
        job: uploadJobticket.waitForJob()
    })

Po wejściu na stronę /api/jobtickets funkcja się wykonuje oraz można pobrać zawartość JSON przy pomocy fetch.

Idąc tym tropem chciałem pobrać numer zamówienia ze strony Klienta i dodać ją do drugiego punktu końcowego /api/order (aplikacja będzie docelowo w iframe na stronie gdzie ten numer występuje) .
Punkt końcowy:

Kopiuj
let data = {
    "result": "ok",
    "test" : "test"
}

app.get('/api/order', (req, res) => {
    res.json(data)  
}
    )

Zawartość JSON pojawia się na stronie /api/order i można ją pobrać przy pomocy fetch ale problem pojawia się jak chcę dodać nowy wpis od strony klienta przy użyciu metod POST lub PUT:

Kopiuj
const OrderId = parent.document.getElementById("nrZam").innerHTML;
const data = {
    "order": OrderId,
};
const url = '/api/order'

const headers = new Headers();
headers.append("Content-Type", "application/json");


fetch(url, {
        method: "post",
        body: JSON.stringify(data),
        headers: {
            'Content-Type': 'text/json',
        }
    })
    .then(res => {
        if (res.ok) {
            console.log(res.headers.get("Content-Type"))
            console.log("Połączenie Aktywne")
            return res.json()

        } else {
            return Promise.reject(`Http error: ${res.status}`)
        }
    })
    .then(res =>
        console.log("Status połączenia: " + JSON.stringify(res)),

    )

wynik w konsoli mam taki:


text/html; charset=utf-8

Połączenie Aktywne

VM97:1 Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
Promise.then (asynchronicznie)

Pobieranie – ładowanie zostało zakończone: POST „http://127.0.0.1:3000/api/order”.


Okazuje się że przeglądarka zwraca błąd 404 stąd znak html'a "<" co jest zapewne przyczyną ale nie potrafię zlokalizować błędu, a siedzę przy tym już od 2 dni. Znalazłem 2 możliwe przyczyny błędu 404: nieprawidłowy adres lub błędy w trasie - niestety nigdzie takich nie wychwyciłem. Może macie lepsze oko... z góry dzięki za pomoc

1programmer
  • Rejestracja:prawie 5 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
  • Postów:525
0

Z tego co wkleiłeś, to nie widać, żebyś miał endpointa z path /api/order, który obsługuje metodę POST, więc stąd pewnie 404.


Programować muszę, bo się uduszę
Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0
szafran98 napisał(a):

Z tego co wkleiłeś, to nie widać, żebyś miał endpointa z path /api/order, który obsługuje metodę POST, więc stąd pewnie 404.

a to ?

Kopiuj
app.get('/api/order', (req, res) => {
    res.json(data)  
}
    )

1programmer
  • Rejestracja:prawie 5 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
  • Postów:525
1

No to jest endpoint obsługujący GET. Tu masz w docsach wyjaśnione https://expressjs.com/en/starter/basic-routing.html


Programować muszę, bo się uduszę
Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0
szafran98 napisał(a):

No to jest endpoint obsługujący GET. Tu masz w docsach wyjaśnione https://expressjs.com/en/starter/basic-routing.html

"facepalm"....oczywiście! dzieki :)

Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0

Dodałem ten endpoint:

Kopiuj
app.put('/api/order', (req, res) => {
    res.json(data) 
})

W konsoli niby wszystko gra:


Pobrałem numer zamówienia: 31023
application/json; charset=utf-8
Połączenie Aktywne
Status połączenia: "ok"
Pobieranie – ładowanie zostało zakończone: PUT „http://127.0.0.1:3000/api/order”.


ale zawartość na stronie order/get nie została zmieniona

Czy to normalne zachowanie ? Zakładałem że metody POST i PUT służą do modyfikacji danych a nie tylko ich pobierania.

edytowany 1x, ostatnio: Bart Eagle
1programmer
  • Rejestracja:prawie 5 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
  • Postów:525
0

No to przecież jak używasz Mongose, to masz MongoDB, a w PUT po prostu zwracasz jakieś data. W ogóle nie widać, żebyś dokonywał jakichś modyfikacji dokumentu w bazie, więc to normalne, że nic się nie zmieniło. Samo się nie zmieni przecież.

Ogólnie polecam na początek zaznajomić się z bazami relacyjnymi SQL (MySQL, PostgreSQL) zamiast od razu iść na głęboką wodę z NoSQL.


Programować muszę, bo się uduszę
edytowany 1x, ostatnio: 1programmer
Bart Eagle
  • Rejestracja:ponad 8 lat
  • Ostatnio:około rok
  • Postów:35
0
szafran98 napisał(a):

No to przecież jak używasz Mongose, to masz MongoDB, a w PUT po prostu zwracasz jakieś data. W ogóle nie widać, żebyś dokonywał jakichś modyfikacji dokumentu w bazie, więc to normalne, że nic się nie zmieniło. Samo się nie zmieni przecież.

Dzięki, już doszedłem do tego i zmieniłem nieco koncepcję. Nie chciałbym w tym projekcie korzystać z bazy danych - potrzebuje tylko jedną wartość, która będzie się zmieniać. Nowy wątek:
Wyciągnięcie zmiennej z app.post w node.js

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.