Funkcja na serwerze wywoływana przez klienta

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?

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.

0

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

0

Kod całej działającej funkcji:

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);
        
             });
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.

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ć :)

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.

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?

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/

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.

0

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

0

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

app.get('/api/jobtickets', (req, res) => res.json({
    "result": "ok",
    "job": uploadJobticket.waitForJob()
}))
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:

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:

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

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.

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 ?

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

1

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

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 :)

0

Dodałem ten endpoint:

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.

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.

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

1 użytkowników online, w tym zalogowanych: 0, gości: 1