Este artículo describe el método para obtener parámetros de obtención de servlet en las solicitudes de publicación de AJAX en los datos del formulario y la carga útil de la solicitud. Compártelo para su referencia, como sigue:
En la solicitud HTTP, si se trata de una solicitud GET, el parámetro de formulario se adjunta a la URL en forma de nombre = valor y nombre1 = valor1. Si se trata de una solicitud posterior, el parámetro de formulario está en el cuerpo de solicitud y también está en el cuerpo de solicitud en forma de nombre = valor y nombre1 = valor1. A través de las herramientas de desarrollador de Chrome, puede ver lo siguiente (aquí hay un formulario legible, no un formato de solicitud de protocolo de solicitud HTTP real):
Obtenga solicitud:
RequestUrl: http: //127.0.0.1: 8080/test/test.do? Name = mikan & direction = streetRequest Method: getStatus Code: 200 okrequest HeadersAccept: Text/Html, Application/XHTML+XML, Aplicación/XML; Q = 0.9, Image/WebP,*/*; Q = 0.8ACTECT-ENCODING: GZIP, Deflate, SDCHACECT-Language: ZH-CN, ZH; Q = 0.8, En; Q = 0.6AlexatoolBar-ALX_NS_NS_NS_NS Ph: alexatoolbar/alxg-3.2connection: keep-alivecookie: jSessionID = 74ac93f9f572980b6fc10474cd8edd8dhost: 127.0.0.1: 8080Referer: http: //127.0.0.1: 8080/test/test/test/jspuse (Windows NT 6.1) AppleWebkit/537.36 (khtml, como gecko) Chrome/33.0.1750.149 Safari/537.36Query String ParametersName: Mikanaddress: StreetResponse HeadersContent-Lengthing: 2Date: Sun, 11 de mayo de 2014 10:42:38 Gmtserver: APATYOTOT
Solicitud de publicación:
RequestUrl: http://127.0.0.1:8080/test/test.dorequest Método: Código poststatus: 200 okrequest HeaderSacept: Text/Html, Application/XHTML+XML, Aplicación/XML; Q = 0.9, Image/WebP,*/*; Q = 0.8acept-Ecoding: GZIP, Deflate, S DCHACCEPTIGE: ZH-CN, ZH; Q = 0.8, EN; Q = 0.6AXATOOLBAR-ALX_NS_PH: AlexatoolBar/Alxg-3.2cache-Control: Max-Age = 0Connection : Keep-alivecontent-longitud: 25Content-type: aplicación/x-www-form-urlencodedcookie: jSessionID = 74AC93F9F572980B6FC10474CD8 Edd8dhost: 127.0.0.1: 8080origin: http: //127.0.0.1: 8080Referer: http: //127.0.0.1: 8080/test/index.jspuser-agent: mozilla/5.0 (Windows NT 6.1) AppleWebkit/537.36 (khtml, como gecko) Chrome/33.0.1750.149 Safari/537.36form DataName: Mikanaddress: StreetResponse HeadersContent-Longitud: 2 Date: Sun, 11 de mayo de 2014 11:05:33 GMTSERVER: APACECE COYET
Aquí debemos tener en cuenta que el tipo de contenido de la solicitud posterior es la aplicación/X-www-form-urlencoded, y el parámetro está en el cuerpo de la solicitud, es decir, los datos de formulario en la solicitud anterior.
En un servlet, los parámetros de formulario se pueden obtener mediante request.getParameter(name) .
Y si usa solicitud de publicación de AJAX nativa:
función getxmlhttprequest () {var xhr; if (window.activexObject) {xhr = new ActiveXObject ("Microsoft.xmlhttp"); } else if (window.xmlhttprequest) {xhr = new xmlhttprequest (); } else {xhr = null; } return xhr;} function save () {var xhr = getxmlhttprequest (); XHR.OPEN ("POST", "http://127.0.0.1:8080/test/test.do"); var data = "name = mikan & direction = street ..."; XHR.SEND (datos); xhr.onreadyStateChange = function () {if (xhr.readyState == 4 && xhr.status == 200) {alert ("returned:"+ xhr.responsetext); }};}A través de las herramientas de desarrollador de Chrome, consulte el encabezado de solicitud de la siguiente manera:
RequestUrl: http://127.0.0.1:8080/test/test.dorequest Método: Código poststatus: 200 okrequest HeaderSaccept:*/*Aceptar-Ecoding: Gzip, Deflate, SdChaccept-Language: Zh-Cn, Zh; Q = 0.8, en; Q = 0.6alexatoolBar-Alx_ns_Ph: AlexatoolBar/alxg-3.2Connection: Keep-aliveContent-longitud: 28Content-type: TPE: TPE: Ext/Plain; Charset = UTF-8Cookie: JSessionID = C40C7823648E952E7C6F7D2E687A0A89HOST: 127.0.0.1: 8080O Rigin: http: //127.0.0.1: 8080Referer: http: //127.0.0.1: 8080/test/index.jspuser-agent: Mozilla/5.0 (Windows NT 6.1) AppleWebkit/537.36 (khtml, como gecko) Chrome/33.0.1750.149 Safari/537.36Request PayloadName = Mikan & Dirección: APOYTERSCONTENT-LENTITA: 2 Date: Sun, 11 de mayo de 2014 11:49:23 Gmtserver
Tenga en cuenta que el tipo de contenido solicitado es text/plain;charset=UTF-8 , y el parámetro del formulario de solicitud está en requestpayload.
Entonces request.getParameter(name) en el servlet está vacío. ¿Por qué? ¿Y cómo se deben obtener tales parámetros?
Para comprender este problema, busqué información y leí el código fuente de Tomcat7.0.53 en el procesamiento de parámetros de solicitud, y finalmente descubrí lo que estaba sucediendo.
Al enviar solicitudes de formulario de publicación HTTP, el tipo de contenido utilizado es application/x-www-form-urlencoded , y si no se especifica la solicitud de solicitud de encabezado de solicitud, el tipo de contenido utilizado por defecto es text/plain;charset=UTF-8 .
Porque Tomcat realiza un "procesamiento especial" para contenido multipart/formulario (carga de archivo) y aplicación/x-www-form-urlencoded (solicitud posterior). Echemos un vistazo al código de procesamiento relevante a continuación.
La clase de implementación de la clase HttpServletRequest de Tomcat es org.apache.catalina.connector.request (en realidad org.apache.coyote.request), y su método de procesamiento de parámetros de solicitud está protected void parseParameters() . Los códigos de procesamiento para el contenido de múltiple/forma de formulario (carga de archivo) y la aplicación/x-www-form-urlencoded (solicitud posterior) en este método son los siguientes:
ProtectedVoid parseParameters () {// omitir algunos código ... parámetros.handleQueryParameters (); // Aquí están los parámetros de procesamiento en la URL // omitir parte del código ... if ("multipart/formy-data" .equals (contentType)) {// Aquí está el archivo de procesamiento de la solicitud de carga parseParts ();; éxito = verdadero; devolver; } if (! ("Application/X-WWW-Form-Urlencoded" .Equals (ContentType)))) {// Aquí está el procesamiento de los parámetros de solicitud de publicación // omitir parte del código ... try {if (readPostBody (FormData, len)! = Len) {// Lea el retorno del cuerpo de la solicitud; }} Catch (IOException e) {// Client Disconnect if (context.getLogger (). ISDEBUGENABLED ()) {context.getLogger (). Debug (sm.getString ("coyoterequest.parseparaLeters"), e); } devolver; } parámetros.processParameters (FormData, 0, len); // Procese el parámetro de solicitud de publicación y colóquelo en el requestparameter en el mapa (es decir, el mapa obtenido por request.getParametermap, request.getParameter (name) también se obtiene de este mapa) // omitir parte del código ...} protegido int readpostbody (byte body [], intent lenException {int offested = 0; do {int inputLen = getStream (). Read (cuerpo, offset, len - offset); if (inputLen <= 0) {return offset; } offset += inputLen; } while ((len - offset)> 0); devolver len;} En el código anterior, podemos ver que la solicitud posterior al tipo de contenido no es Application/X-WWW-Form-Urlencoded no leerá los datos del cuerpo de la solicitud y realizará el procesamiento de parámetros correspondientes, es decir, los datos del formulario no se analizarán y se colocarán en el mapa de parámetros de solicitud. Por lo tanto, no se puede obtener a través de request.getParameter(name) .
Entonces, ¿cómo obtenemos los parámetros enviados de esta manera?
Por supuesto, es el método más primitivo para leer el flujo de entrada para obtenerlo, como se muestra a continuación:
PrivateString getRequestPayLoad (httpservletrequest req) {stringBuildersb = new StringBuilder (); try (bufferedReaderReader = req.getReader ();) {char [] buff = new Char [1024]; intlen; while ((len = lector.read (buff))! = -1) {sb.append (buff, 0, len); }} catch (ioException e) {E.PrintStackTrace (); } returnb.ToString ();}Por supuesto, las solicitudes de publicación con el conjunto de aplicaciones/X-WWW-form-Urlencoded también se pueden obtener de esta manera.
Por lo tanto, cuando se usa la solicitud de publicación de AJAX nativa, debe establecer explícitamente el encabezado de solicitud, es decir:
XHR.SetRequestHeader ("Content-type", "Application/X-WWW-form-urlencoded"); Además, si usa jQuery, uso la versión 1.11.0 para probarla. $.ajax post no necesita establecer este encabezado de solicitud explícitamente, y no lo he probado yo mismo para otras versiones. Creo que las versiones después de 1.11.0 no necesitan establecerse. Pero algunos antes pueden no estar seguros. Esto no ha sido probado.
posdata:
Realmente entendí por qué el servidor hace un procesamiento especial para el envío de formulario y la carga de archivos, porque los datos de envío de formulario son un par de valores de nombre, y el tipo de contenido es aplicación/X-www-form-urlencoded, mientras que el servidor de carga de archivos necesita un procesamiento especial. El formato de datos de las solicitudes de publicación ordinarias (tipo de contenido no es aplicación/X-www-form-urlencoded) no es fijo, y no es necesariamente un par de valores de nombre, por lo que el servidor no puede conocer el método de procesamiento específico, por lo que solo puede analizar mediante la obtención del flujo de datos original.
Cuando JQuery ejecuta una solicitud de publicación, establece el tipo de contenido en Application/X-WWW-Form-URLEncoded, para que el servidor pueda analizar correctamente. Cuando se usa la solicitud AJAX nativa, si no se muestra el tipo de contenido, el valor predeterminado es texto/simple. En este momento, el servidor no sabe cómo analizar los datos, por lo que solo puede analizar los datos de solicitud obteniendo el flujo de datos original.
Para obtener más información sobre los algoritmos Java, los lectores interesados en este sitio pueden ver los temas: "Resumen de las habilidades de programación de redes de Java", "Tutoriales sobre estructuras de datos de Java y algoritmos", "Resumen de habilidades de nodo DOM de operación Java", "Resumen del archivo de Java y las habilidades de operación de directorio" y "Summary of Java Cache Skills"
Espero que este artículo sea útil para la programación Java de todos.