บทความนี้อธิบายถึงวิธีการของ servlet ที่ได้รับพารามิเตอร์ในการร้องขอโพสต์ AJAX ในข้อมูลฟอร์มและขอน้ำหนักบรรทุก แบ่งปันสำหรับการอ้างอิงของคุณดังนี้:
ในคำขอ HTTP หากเป็นคำขอ GET พารามิเตอร์ฟอร์มจะถูกแนบกับ URL ในรูปแบบของชื่อ = value & name1 = value1 หากเป็นคำขอโพสต์พารามิเตอร์แบบฟอร์มจะอยู่ในตัวคำขอและยังอยู่ในตัวคำขอในรูปแบบของชื่อ = value & name1 = value1 ผ่านเครื่องมือนักพัฒนา Chrome คุณสามารถดูสิ่งต่อไปนี้ (นี่คือรูปแบบที่อ่านได้ไม่ใช่รูปแบบคำขอโปรโตคอลคำขอ HTTP จริง):
รับคำขอ:
RequestUrl: http: //127.0.0.1: 8080/test/test.do? name = mikan & address = วิธีการ streetrequest: getstatus รหัส: 200 okrequest headersaccept: text/html, application/xhtml+xml, application/xml; q = 0.9, image/webp,*/*; q = 0.8accept-encoding: gzip, deflate, sdchaccept-language: zh-cn, zh; q = 0.8, en; pH: Alexatoolbar/ALXG-3.2Connection: Keep-Alivecookie: jsessionId = 74Ac93f9f572980B6FC10474CD8EDDD8DHOST: 127.0.0.1: 8080Referer: http: //127.0.0.1: 8080/ทดสอบ/ดัชนี 6.1) Applewebkit/537.36 (khtml, เช่น Gecko) Chrome/33.0.1750.149 Safari/537.36 Quary Parametersname: Mikanaddress: StreetResponse headerscontent-Length: 2Date: Sun, 11 พฤษภาคม 2014
คำขอโพสต์:
RequestUrl: http://127.0.0.1:8080/test/test.dorequest วิธีการ: รหัสหลังสเตทัส: 200 okrequest headersaccept: text/html, application/xhtml+xml, application/xml; q = 0.9, image/webp,*/*; q = 0.8accept-encoding: GZIP, deflate, s Dchaccept-Language: zh-cn, zh; q = 0.8, en; q = 0.6alexatoolbar-alx_ns_ph: Alexatoolbar/alxg-3.2cache-control: max-age = 0connection - Keep-Alivecontent-Length: 25content-type: แอปพลิเคชัน/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, เช่น Gecko) Chrome/33.0.1750.149 Safari/537.36 ฟอร์
ที่นี่เราควรทราบว่าประเภทเนื้อหาของคำขอโพสต์คือแอปพลิเคชัน/x-www-form-urlencoded และพารามิเตอร์อยู่ในตัวคำขอนั่นคือข้อมูลแบบฟอร์มในคำขอข้างต้น
ใน servlet พารามิเตอร์แบบฟอร์มสามารถรับได้โดย request.getParameter(name)
และหากใช้คำขอโพสต์ Ajax ดั้งเดิม:
ฟังก์ชั่น getxmlhttprequest () {var xhr; if (window.activexobject) {xhr = new ActiveXObject ("microsoft.xmlhttp"); } อื่นถ้า (window.xmlhttprequest) {xhr = ใหม่ xmlhttprequest (); } else {xhr = null; } return xhr;} function save () {var xhr = getxmlhttpRequest (); xhr.open ("โพสต์", "http://127.0.0.1:8080/test/test.do"); var data = "name = mikan & address = street ... "; XHR.Send (ข้อมูล); xhr.onreadyStateChange = function () {ถ้า (xhr.readystate == 4 && xhr.status == 200) {แจ้งเตือน ("ส่งคืน:"+ xhr.responsetext); -ผ่านเครื่องมือนักพัฒนาของ Chrome ดูส่วนหัวคำขอดังนี้:
RequestUrl: http://127.0.0.1:8080/test/test.dorequest วิธีการ: รหัสหลังสเตทัส: 200 okrequest headersaccept:*/*ยอมรับการเข้ารหัส: gzip, deflate, sdchaccept-language: zh-cn, zh; q = 0.8, en; q = 0.6alexatoolbar-alx_ns_ph: Alexatoolbar/alxg-3.2connection 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, เช่น Gecko) Chrome/33.0.1750.149 Safari/537.36Request Payloadname = Mikan & ที่อยู่ = StreetResponse headers
โปรดทราบว่าประเภทเนื้อหาที่ร้องขอคือ text/plain;charset=UTF-8 และพารามิเตอร์แบบฟอร์มคำขออยู่ใน requestpayload
จากนั้น request.getParameter(name) ใน servlet จะว่างเปล่า ทำไม และควรได้รับพารามิเตอร์ดังกล่าวอย่างไร?
เพื่อที่จะเข้าใจปัญหานี้ฉันค้นหาข้อมูลบางอย่างและอ่านซอร์สโค้ดของ TomCat7.0.53 ในการประมวลผลพารามิเตอร์คำขอและในที่สุดก็รู้ว่าเกิดอะไรขึ้น
เมื่อส่งคำขอแบบฟอร์มโพสต์ HTTP ประเภทเนื้อหาที่ใช้คือ application/x-www-form-urlencoded และหากไม่ได้ระบุ requestheader ส่วนหัวของคำขอประเภทเนื้อหาที่ใช้โดยค่าเริ่มต้นคือ text/plain;charset=UTF-8
เนื่องจาก TOMCAT ทำ "การประมวลผลพิเศษ" สำหรับเนื้อหาหลายประเภท/ฟอร์ม-ข้อมูล (การอัปโหลดไฟล์) และแอปพลิเคชัน/x-www-form-urlencoded (คำขอโพสต์) มาดูรหัสการประมวลผลที่เกี่ยวข้องด้านล่าง
คลาสการใช้งานของคลาส httpservletrequest ของ Tomcat คือ org.apache.catalina.connector.request (จริง ๆ แล้ว org.apache.coyote.request) และวิธีการประมวลผล protected void parseParameters() รหัสการประมวลผลสำหรับ multipart/form-data ประเภทเนื้อหา (การอัปโหลดไฟล์) และแอปพลิเคชัน/x-www-form-urlencoded (คำขอโพสต์) ในวิธีนี้มีดังนี้:
ProtectedVoid parseparameters () {// ละเว้นรหัสบางส่วน ... พารามิเตอร์. handleQueryParameters (); // นี่คือพารามิเตอร์การประมวลผลใน URL // ส่วนหนึ่งของรหัส ... ถ้า ("multipart/form-data" ความสำเร็จ = จริง; กลับ; } if (! ("แอปพลิเคชัน/x-www-form-urlencoded" .equals (contentType))) {// นี่คือการประมวลผลพารามิเตอร์การร้องขอโพสต์ // ละเว้นส่วนหนึ่งของรหัส ... ลอง {ถ้า (readpostbody (formdata, len)! = len) {// อ่านข้อมูล }} catch (ioexception e) {// ไคลเอ็นต์ตัดการเชื่อมต่อถ้า (context.getLogger (). isdebugenabled ()) {context.getLogger (). debug (sm.getString ("coyoterequest.parsparameters"), e); } กลับ; } parameters.processParameters (formData, 0, len); // ประมวลผลพารามิเตอร์การร้องขอโพสต์และวางไว้ในคำขอพารามิเตอร์ในแผนที่ (เช่นแผนที่ที่ได้รับจาก request.getParametermap, request.getParameter (ชื่อ) ยังได้รับจากแผนที่นี้ด้วย) // ละเว้นส่วนหนึ่งของรหัส ... } ทำ {int inputlen = getStream () อ่าน (ร่างกาย, ออฟเซ็ต, เลน - ออฟเซ็ต); if (inputlen <= 0) {return rofts; } Offset += InputLen; } ในขณะที่ ((Len - Offset)> 0); กลับ len;} จากรหัสข้างต้นเราจะเห็นว่าการร้องขอโพสต์ของประเภทเนื้อหาไม่ใช่แอปพลิเคชัน/X-WWW-FORM-URLENCODED จะไม่อ่านข้อมูลร่างกายคำขอและดำเนินการประมวลผลพารามิเตอร์ที่สอดคล้องกันนั่นคือข้อมูลแบบฟอร์มจะไม่ถูกแยกวิเคราะห์และวางไว้ในแผนที่พารามิเตอร์คำขอ ดังนั้นจึงไม่สามารถรับได้ผ่าน request.getParameter(name)
แล้วเราจะได้รับพารามิเตอร์ที่ส่งมาด้วยวิธีนี้ได้อย่างไร?
แน่นอนว่ามันเป็นวิธีดั้งเดิมที่สุดในการอ่านสตรีมอินพุตเพื่อรับดังที่แสดงด้านล่าง:
Privatestring getRequestPayLoad (httpservletRequest req) {stringbuildersb = new StringBuilder (); ลอง (bufferedReaderReader = req.getReader ();) {char [] buff = new Char [1024]; Intlen; ในขณะที่ ((len = reader.read (buff))! = -1) {sb.append (buff, 0, len); }} catch (ioexception e) {e.printstacktrace (); } returnsb.toString ();}แน่นอนว่าการร้องขอโพสต์ด้วยชุดแอปพลิเคชัน/X-WWW-FORM-URLENCODED สามารถรับได้ด้วยวิธีนี้
ดังนั้นเมื่อใช้คำขอโพสต์ Ajax แบบดั้งเดิมคุณต้องตั้งค่าส่วนหัวคำขออย่างชัดเจนนั่นคือ:
XHR.SetRequestHeader ("ประเภทเนื้อหา", "แอปพลิเคชัน/x-www-form-urlencoded"); นอกจากนี้หากคุณใช้ jQuery ฉันใช้เวอร์ชัน 1.11.0 เพื่อทดสอบ คำขอ $.ajax post ไม่จำเป็นต้องตั้งค่าส่วนหัวคำขอนี้อย่างชัดเจนและฉันยังไม่ได้ทดสอบด้วยตัวเองสำหรับเวอร์ชันอื่น ฉันเชื่อว่าไม่จำเป็นต้องตั้งค่าเวอร์ชันหลังจาก 1.11.0 แต่บางคนก่อนหน้านี้อาจไม่แน่นอน สิ่งนี้ยังไม่ได้รับการทดสอบ
Postscript:
ฉันเข้าใจจริง ๆ ว่าทำไมเซิร์ฟเวอร์จึงทำการประมวลผลพิเศษสำหรับการส่งแบบฟอร์มและการอัปโหลดไฟล์เนื่องจากข้อมูลการส่งแบบฟอร์มเป็นคู่ชื่อชื่อและประเภทเนื้อหาคือแอปพลิเคชัน/x-www-form-urlencoded ในขณะที่เซิร์ฟเวอร์อัปโหลดไฟล์ต้องการการประมวลผลพิเศษ รูปแบบข้อมูลของคำขอโพสต์สามัญ (ประเภทเนื้อหาไม่ใช่แอปพลิเคชัน/X-WWW-FORM-URLENCODED) ไม่ได้รับการแก้ไขและไม่จำเป็นต้องเป็นคู่ชื่อชื่อดังนั้นเซิร์ฟเวอร์จึงไม่สามารถรู้วิธีการประมวลผลเฉพาะดังนั้นจึงสามารถแยกวิเคราะห์ได้โดยการสตรีมข้อมูลดั้งเดิม
เมื่อ jQuery ดำเนินการตามคำขอโพสต์จะตั้งค่าประเภทเนื้อหาเป็นแอปพลิเคชัน/x-www-form-urlencoded ดังนั้นเซิร์ฟเวอร์สามารถแยกวิเคราะห์ได้อย่างถูกต้อง เมื่อใช้คำขอ AJAX ดั้งเดิมหากไม่แสดงประเภทเนื้อหาค่าเริ่มต้นคือข้อความ/ธรรมดา ในเวลานี้เซิร์ฟเวอร์ไม่ทราบวิธีการแยกวิเคราะห์ข้อมูลดังนั้นจึงสามารถแยกวิเคราะห์ข้อมูลคำขอได้โดยการรับสตรีมข้อมูลต้นฉบับ
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับอัลกอริทึม Java ผู้อ่านที่สนใจในเว็บไซต์นี้สามารถดูหัวข้อ: "สรุปทักษะการเขียนโปรแกรมเครือข่าย Java", "บทช่วยสอนเกี่ยวกับโครงสร้างข้อมูล Java และอัลกอริทึม", "ทักษะการดำเนินงานของ Java การดำเนินงาน"
ฉันหวังว่าบทความนี้จะเป็นประโยชน์กับการเขียนโปรแกรม Java ของทุกคน