2013-03-15 20 views
39

Próbuję obsłużyć wysłanie żądania posta na mój serwer node.js. Plik JavaScript o nazwie server.js wyświetla formularz w przeglądarce. Chcę uzyskać dostęp do wartości formularza po ich opublikowaniu w backendu node.js.Jak obsłużyć żądanie POST w pliku node.js

Formularz zawiera nazwę użytkownika, repozytorium i oddział. Po przesłaniu formularza chcę przywrócić dane z powrotem do użytkownika.

Kod server.js:

var http = require('http'); 

http.createServer(function (request, response) { 
response.writeHead(200, {'Content-Type': 'text/html'}); 
response.end('<html><body>' 
    + '<h1>XYZ Repository Commit Monitor</h1>' 
    + '<form method="post" action="." enctype="application/x-www-form-urlencoded"><fieldset>' 
    + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>' 
    + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>' 
    + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>' 
    + '<div><input id="ListCommits" type="submit" value="List Commits" /></div>' 
    + '</fieldset></form>' 
    + '</body></html>'); 
}).listen(8124); 

console.log('Server running at http://127.0.0.1:8124/'); 
+12

Zdecydowanie zaleca się korzystanie z ramy (nawet niskiego poziomu) do budowania aplikacji przy użyciu węzła. Osobiście korzystam z Express (http://expressjs.com/), ale są też inne opcje, jeśli wybierzesz. Pozwala między innymi na łatwe obsługiwanie różnych rodzajów i tras zgłoszeń, a także treści statycznych. –

+0

Zobacz http://stackoverflow.com/questions/6158933/http-post-request-in-node-js – user568109

+0

Możesz zobaczyć prosty przykład jak obsługiwać HTTP POST z Express.js w moim blogu http: // hectorcorrea .com/blog/introduction-to-node-js –

Odpowiedz

129

Zamierzam użyć kodu podanego i udzielić odpowiedzi dokładniejsze niż co pokryte swoje pytanie na pobyt ludzi w odległej przyszłości. Dostarczę również odpowiedź, która używa "Vanilla JS" (http://www.vanilla-js.com/), ponieważ uważam, że zbyt wielu hipstersów mówi "używaj frameworku", gdy próbujesz dowiedzieć się, jak to działa. Myślę, że powodem, dla którego to robią, jest to, że ktoś powiedział im, aby "korzystali z ram", kiedy uczyli się, jak to działa. Ponieważ nie są hakerami, nie starają się zrozumieć procesu, więc bardzo często wielu z nich nie wie, jak to zrobić na własną rękę, bez frameworka (stąd wszechobecne "wykorzystanie frameworka"). Staniesz się lepszym hackerem, rozumiejąc, co dzieje się pod maską i mam nadzieję, że ta odpowiedź pomoże ci w tym względzie.

Teraz, gdy chcesz, aby dane POST (formularz) były akceptowane za pośrednictwem wyprowadzanego formularza, konieczne jest zapewnienie mechanizmu routingu na serwerze. Oznacza to, że powiesz swojemu serwerowi, aby udostępnił formularz osobom odwiedzającym Twoją witrynę, ale wtedy, gdy użytkownik prześle formularz, Węzeł przekieruje dane POST do niewielkiej funkcji przetwarzania. Najpierw dostarczyłem pełną odpowiedź, a następnie przeanalizowałem ją dalej, aby uwzględnić osoby, które chcą uczyć się z kodu.

var http = require('http'); 
var qs = require('querystring'); 
var formOutput = '<html><body>' 
    + '<h1>XYZ Repository Commit Monitor</h1>' 
    + '<form method="post" action="inbound" enctype="application/x-www-form-urlencoded"><fieldset>' 
    + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>' 
    + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>' 
    + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>' 
    + '<div><input id="ListCommits" type="submit" value="List Commits" /></div></fieldset></form></body></html>'; 
var serverPort = 8124; 
http.createServer(function (request, response) { 
    if(request.method === "GET") { 
    if (request.url === "/favicon.ico") { 
     response.writeHead(404, {'Content-Type': 'text/html'}); 
     response.write('<!doctype html><html><head><title>404</title></head><body>404: Resource Not Found</body></html>'); 
     response.end(); 
    } else { 
     response.writeHead(200, {'Content-Type': 'text/html'}); 
     response.end(formOutput); 
    } 
    } else if(request.method === "POST") { 
    if (request.url === "/inbound") { 
     var requestBody = ''; 
     request.on('data', function(data) { 
     requestBody += data; 
     if(requestBody.length > 1e7) { 
      response.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'}); 
      response.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>'); 
     } 
     }); 
     request.on('end', function() { 
     var formData = qs.parse(requestBody); 
     response.writeHead(200, {'Content-Type': 'text/html'}); 
     response.write('<!doctype html><html><head><title>response</title></head><body>'); 
     response.write('Thanks for the data!<br />User Name: '+formData.UserName); 
     response.write('<br />Repository Name: '+formData.Repository); 
     response.write('<br />Branch: '+formData.Branch); 
     response.end('</body></html>'); 
     }); 
    } else { 
     response.writeHead(404, 'Resource Not Found', {'Content-Type': 'text/html'}); 
     response.end('<!doctype html><html><head><title>404</title></head><body>404: Resource Not Found</body></html>'); 
    } 
    } else { 
    response.writeHead(405, 'Method Not Supported', {'Content-Type': 'text/html'}); 
    return response.end('<!doctype html><html><head><title>405</title></head><body>405: Method Not Supported</body></html>'); 
    } 
}).listen(serverPort); 
console.log('Server running at localhost:'+serverPort); 

A teraz, aby wyjaśnić, dlaczego zrobiłem to, co zrobiłem.

var http = require('http'); 
var qs = require('querystring'); 

Najpierw dodamy wbudowany moduł "querystring" w celu przeanalizowania rzeczywistych danych formularza.

var formOutput = '<html><body>' 
    + '<h1>XYZ Repository Commit Monitor</h1>' 
    + '<form method="post" action="/inbound" enctype="application/x-www-form-urlencoded"><fieldset>' 
    + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>' 
    + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>' 
    + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>' 
    + '<div><input id="ListCommits" type="submit" value="List Commits" /></div></fieldset></form></body></html>'; 
var serverPort = 8124; 

Przesunąłem wynik formularza powyżej naszego serwera/routingu/mechanizmu obsługi formularzy, ponieważ logika jest znacznie łatwiejsza do odczytania. Przesunąłem tu także informacje o portach nasłuchiwania serwera, ponieważ trzeba to zmienić tylko w jednym miejscu, zamiast wielu poniżej.

http.createServer(function (request, response) { 

(zwykle skrócić parametry tej funkcji na "zamów" i "res", ale to tylko moje preferencje.)

if(request.method === "GET") { 
    if (request.url === "/favicon.ico") { 
     response.writeHead(404, {'Content-Type': 'text/html'}); 
     response.write(notFound); 
     response.end(); 

Tutaj podaję prosty routing przykładem. W tym przypadku nasz serwer nasłuchuje żądań dla "favicon.ico" - próśb złożonych wraz z prawie wszystkimi początkowymi żądaniami strony internetowej przez wszystkie główne przeglądarki. Ten plik to mała ikona widoczna na kartach każdej odwiedzanej strony internetowej. Dla naszych celów nie musimy obsługiwać favikona, ale będziemy obsługiwać żądania przychodzące, aby pokazać kilka podstawowych mechanizmów routingu.

} else { 
     response.writeHead(200, {'Content-Type': 'text/html'}); 
     response.end(formOutput); 
    } 

Jeśli użytkownicy podkreślić swoją przeglądarkę do jakiegokolwiek innego zasobu na serwerze z domyślnej metody GET (oprócz „favicon.ico” po prostu obsługiwane powyżej), będziemy służyć im formę.

} else if(request.method === "POST") { 

W przeciwnym razie, jeśli użytkownicy są skierowane POST na serwerze, to jest bardzo prawdopodobne, że złożyły one pobierane formę z poprzedniego żądania GET.

if (request.url === "/inbound") { 

Tutaj jesteśmy nasłuchiwanie żądań przychodzących zwanych „/ przychodzące”, który - jeśli złapał trochę szczegółowo powyżej - jest to „działanie” z naszego formularza HTML. Jak być może wiesz, "akcja" formularza informuje przeglądarkę, gdzie wysłać dane formularza.

 var requestBody = ''; 
     request.on('data', function(data) { 
     requestBody += data; 
     if(requestBody.length > 1e7) { 
      response.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'}); 
      response.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>'); 
     } 
     }); 
     request.on('end', function() { 
     var formData = qs.parse(requestBody); 

To może wydawać się trochę zagmatwane, ale obiecuję, że nie. Żądania POST można wysyłać w postaci wiadomości wieloczęściowych z przeglądarki klienta. Mając coś tak małego jak kilka zmiennych w formie, prawdopodobnie nigdy nie zobaczysz tego, ale gdy skalujesz ilość obsługiwanych danych, zobaczysz to. Jeśli jesteś spostrzegawczy, zobaczysz także instrukcję if() pytającą o długość danych POST. Złośliwa osoba może zabić twój serwer, przesyłając nieskończony plik, ale nie, jeśli podejmiemy odpowiednie działania. Ogranicza to zawartość danych POST do około dziesięciu megabajtów, ale należy odpowiednio dostosować. Wiedza o tych rzeczach zapobiega przyszłym bólom głowy i nie chcę, abyś miał ból głowy.

 response.writeHead(200, {'Content-Type': 'text/html'}); 
     response.write('<!doctype html><html><head><title>response</title></head><body>'); 
     response.write('Thanks for the data!<br />User Name: '+formData.UserName); 
     response.write('<br />Repository Name: '+formData.Repository); 
     response.write('<br />Branch: '+formData.Branch); 
     response.end('</body></html>'); 
     }); 

Tutaj mamy dane formularzy. Ze względu na naturę Javascript, te nazwy zmiennych to CASE SENSITIVE (takie jak "UserName" zamiast "username"). Oczywiście, możesz zrobić wszystko, co chcesz z tymi danymi (pamiętając o pętli zdarzeń węzła i asynchronicznej naturze).

} 
    response.writeHead(404, 'Resource Not Found', {'Content-Type': 'text/html'}); 
    return response.end('<!doctype html><html><head><title>404</title></head><body>413: Request Entity Too Large</body></html>'); 

Aby kontynuować nasz przykład routingu, co zrobiliśmy tutaj jest wliczone catch-all pod oświadczeniem if() który wysyła klientowi ogólny 404 „nie znaleziono” odpowiadać na każde żądanie POST nie mamy już obsługiwane.

} else { 
    response.writeHead(405, 'Method Not Supported', {'Content-Type': 'text/html'}); 
    return response.end('<!doctype html><html><head><title>405</title></head><body>405: Method Not Supported</body></html>'); 
    } 
}).listen(serverPort); 
console.log('Server running at localhost:'+serverPort); 

A teraz właśnie zakończyliśmy kod, w tym trochę kodu do obsługi żądań przy użyciu dziwnych metod. Jest kilka rzeczy, których nie omówiłem (struktura funkcji, puste dane formularzy itp.), Ale naprawdę istnieje wiele sposobów na osiągnięcie celów. Jako jeden z moich profesorów CS powiedział kiedyś wiele lat temu, istnieje tak wiele sposobów programowania programu, że łatwo jest zobaczyć, kto oszukuje, dzieląc się swoją pracą domową.

Mam nadzieję, że (i każdy inny) zauważysz, że nie jest to jakiś ezoteryczny lub nawet nieco trudny proces robienia rzeczy w Węzłach za pomocą wbudowanych modułów zamiast polegania na zewnętrznych bibliotekach firm trzecich, takich jak Express. Biblioteki te mają swoje miejsce na świecie, ale nie kierują się stadem: Podejmuj świadomą decyzję o kodzie, ponieważ na koniec jesteś odpowiedzialny za to (a nie za osoby w Stack Overflow).

+13

Dlaczego Czy nie mogę zrobić tego 10 razy?;) – Mixthos

+3

Ta myśl się liczy. Dzięki! :) – L0j1k

+3

Wow świetna odpowiedź! Doskonale na początek :) dzięki! – Martin