2013-08-28 21 views
8

Sono nella situazione in cui la mia applicazione deve ispezionare il contenuto/dati/corpo/payload di una richiesta POST senza modificare i risultati delle successive chiamate getParameter.Leggere il corpo POST di HTTPServletRequest E quindi chiamare getParameter in Tomcat

La lettura del corpo dalla inputStream:

Il corpo può essere letto utilizzando l'InputStream da request.getInputStream o BufferedReader da request.getReader.

parametri di lettura del messaggio:

richieste POST di solito includono parametri di richiesta nel corpo della richiesta. Questi possono essere recuperati utilizzando getParameter.

Il problema:

primo getParameter chiamata analizza internamente l'inputStream e inserisce tutti i parametri in un parametro HashMap. Richiede che inputStream contenga ancora i contenuti per l'analisi. Pertanto non è possibile ispezionare il contenuto e avere ancora una chiamata getParameter funzionante.

proposto (ma non sufficiente) Soluzione

Creare un wrapper richiesta che memorizza nella cache l'InputStream e restituisce la cache per getInputStream.

Ho visto che la soluzione è stata suggerita in tutto il Web, ma non funziona, perché getParameter in realtà non chiama getInputStream, ma si riferisce al buffer di input originale nascosto nell'oggetto di richiesta. L'ho provato, sia dall'interno della Servlet che usando un filtro

L'unica soluzione che posso immaginare riguarda la riscrittura di getParameter per analizzare effettivamente l'inputstream memorizzato nella cache manualmente. Ma questa sembra una cattiva idea.

Qualcuno ha qualche alternativa che funzioni? (Questo è Tomcat 5.5) Sembra che dovrebbe essere un caso d'uso comune; Non posso credere quanto sia difficile.

+1

La risposta a questa domanda non è una soluzione. L'ho implementato e non è riuscito a risolvere il problema. Da allora ho letto l'origine di Tomcat e ho capito che getParameter non chiama getInputStream, come ho detto sopra, e quindi non leggerà dalla versione cache dello stream. vedere http://grepcode.com/file/repo1.maven.org/maven2/tomcat/catalina/5.5.23/org/apache/catalina/connector/RequestFacade.java?av=f#342 Io non sono certo perché la gente sembra aver trovato una soluzione. – rewolf

+0

Il metodo 'getParameter' chiama' getInputStream'. Innanzitutto, la chiamata 'getParameter'' parseParameters', quindi 'parseParameters' chiama' readPostBody', quindi 'readPostBody' chiama' getInputStream'. – peakmuma

risposta

1

Come suggerito da @caskey, una possibile soluzione sarebbe utilizzare la riflessione per sostituire l'inputBuffer con un inputbuffer riproducibile. Ma non ho usato questo approccio perché mi sentivo cattivo.

Invece ho creato un wrapper di richiesta in un filtro che legge l'inputstream in una matrice di byte e restituisce un nuovo InputStream che utilizza internamente uno ByteArrayInputStream attorno a quell'array per tutte le chiamate getInputStream.

Dopo aver letto l'inputstream nell'array di byte, creo una mappa dei parametri analizzando il payload. Ho unito la mappa dei parametri della superclasse per supportare i casi GET con i parametri di query. Ho sovrascritto tutti i metodi getParameter *() per utilizzare questa mappa dei parametri.

Ho utilizzato apache.axis.utils.IOUtils.readFully per leggere facilmente il flusso nell'array di byte. E attualmente sto usando javax.servlet.http.HttpUtils.parsePostData per analizzare i dati nella mappa dei parametri. HttpUtils.parsePostData è in realtà deprecato, quindi probabilmente lo sostituirò con una versione migliore quando lo trovo.

Ma questo funziona, sì!

1

(Questo è un gatto piuttosto vecchio, sto assumendo l'aggiornamento a una più moderna non è un'opzione.)

Che cosa si vuole fare richiederà intercettare la costruzione dell'oggetto HttpServletResponse concreto avvolgendo il sottostante InputStream. Il wrapping di InputStream in un flusso di input push-back (o equivalente) è necessario.

Tomcat 5.5 è così vecchio che non riesco nemmeno a pensare come sarebbe stato eseguito "normalmente", ma forse si potrebbe scrivere un filtro che utilizza la riflessione per raggiungere e scambiare l'oggetto InputStream all'interno dell'oggetto di richiesta concreto.

+0

Sì. Sei piuttosto azzeccato con l'idea della riflessione. Ci siamo anche inventati. Ho optato però per un approccio diverso: creare un wrapper di richieste in un filtro che supporti la riproduzione di inputstream. Ho quindi sovrascritto i metodi getParameter *() per leggere da una mappa che è stata creata analizzando l'inputstream/payload. – rewolf

Problemi correlati