RequestDispatcher.forward () กับ HttpServletResponse.sendRedirect ()


คำตอบ:


106

requestDispatcher - ไปข้างหน้า () วิธีการ

  1. เมื่อเราใช้forwardวิธีนี้คำขอจะถูกโอนไปยังทรัพยากรอื่นภายในเซิร์ฟเวอร์เดียวกันเพื่อดำเนินการต่อไป

  2. ในกรณีของforwardเว็บคอนเทนเนอร์จะจัดการการประมวลผลทั้งหมดภายในและไคลเอนต์หรือเบราว์เซอร์จะไม่เกี่ยวข้อง

  3. เมื่อforwardถูกเรียกบนrequestDispatcherอ็อบเจ็กต์เราจะส่งผ่านคำร้องขอและอ็อบเจ็กต์การตอบสนองดังนั้นอ็อบเจ็กต์คำขอเก่าของเราจึงอยู่ในทรัพยากรใหม่ซึ่งจะดำเนินการตามคำขอของเรา

  4. ด้วยสายตาเราไม่สามารถเห็นที่อยู่ที่ส่งต่อได้ แต่เป็นแบบโปร่งใส

  5. โดยใช้วิธีการที่เร็วกว่าforward()sendRedirect

  6. เมื่อเราเปลี่ยนเส้นทางโดยใช้ไปข้างหน้าและเราต้องการใช้ข้อมูลเดียวกันในทรัพยากรใหม่เราสามารถใช้request.setAttribute()เมื่อเรามีวัตถุขอ

sendRedirect

  1. ในกรณีนี้sendRedirectคำขอจะถูกโอนไปยังทรัพยากรอื่นไปยังโดเมนอื่นหรือไปยังเซิร์ฟเวอร์อื่นเพื่อดำเนินการต่อไป

  2. เมื่อคุณใช้sendRedirectคอนเทนเนอร์จะโอนคำขอไปยังไคลเอนต์หรือเบราว์เซอร์ดังนั้น URL ที่ระบุในsendRedirectเมธอดจะมองเห็นได้ว่าเป็นคำขอใหม่สำหรับไคลเอ็นต์

  3. ในกรณีของการsendRedirectโทรคำขอเก่าและอ็อบเจ็กต์การตอบกลับจะหายไปเนื่องจากเบราว์เซอร์ถือว่าเป็นคำขอใหม่

  4. ในแถบที่อยู่เราจะเห็นที่อยู่ที่เปลี่ยนเส้นทางใหม่ มันไม่โปร่งใส

  5. sendRedirectช้ากว่าเนื่องจากต้องใช้การเดินทางรอบพิเศษหนึ่งครั้งเนื่องจากมีการสร้างคำขอใหม่ทั้งหมดและวัตถุคำขอเก่าจะสูญหายไป จำเป็นต้องมีคำขอเบราว์เซอร์สองรายการ

  6. แต่ในsendRedirectกรณีที่เราต้องการใช้ข้อมูลเดียวกันกับทรัพยากรใหม่เราต้องจัดเก็บข้อมูลในเซสชันหรือส่งต่อไปพร้อมกับ URL

ตัวไหนดีครับ?

ขึ้นอยู่กับสถานการณ์ว่าวิธีใดมีประโยชน์มากกว่า

sendRedirectถ้าคุณต้องการควบคุมการโอนไปยังเซิร์ฟเวอร์ใหม่หรือบริบทและมันจะถือว่าเป็นงานใหม่ที่สมบูรณ์แล้วเราไป โดยทั่วไปควรใช้การส่งต่อหากการดำเนินการสามารถทำซ้ำได้อย่างปลอดภัยเมื่อเบราว์เซอร์โหลดหน้าเว็บซ้ำและจะไม่ส่งผลต่อผลลัพธ์

แหล่ง


161

ในโลกของการพัฒนาเว็บคำว่า "เปลี่ยนเส้นทาง" คือการส่งการตอบสนอง HTTP ที่ว่างเปล่าให้กับลูกค้าโดยมีเพียงLocationส่วนหัวที่มี URL ใหม่ซึ่งไคลเอ็นต์ต้องส่งคำขอ GET ใหม่ล่าสุด โดยพื้นฐานแล้ว:

  • ไคลเอนต์ส่งการร้องขอ HTTP some.jspไป
  • เซิร์ฟเวอร์ส่งการตอบกลับ HTTP พร้อมLocation: other.jspส่วนหัว
  • ลูกค้าส่งคำขอ HTTP ไปที่other.jsp(สิ่งนี้จะแสดงในแถบที่อยู่ของเบราว์เซอร์!)
  • เซิร์ฟเวอร์ส่งการตอบกลับ HTTP พร้อมเนื้อหาของother.jsp.

คุณสามารถติดตามได้ด้วยชุดเครื่องมือสำหรับนักพัฒนา builtin / addon ของเว็บเบราว์เซอร์ กด F12 ใน Chrome / IE9 / Firebug และตรวจสอบส่วน "เครือข่าย" เพื่อดู

sendRedirect("other.jsp")ตรงข้างต้นจะทำได้โดย RequestDispatcher#forward()ไม่ส่งการเปลี่ยนเส้นทาง แต่จะใช้เนื้อหาของเพจเป้าหมายเป็นการตอบสนอง HTTP

  • ไคลเอนต์ส่งการร้องขอ HTTP some.jspไป
  • เซิร์ฟเวอร์ส่งการตอบกลับ HTTP พร้อมเนื้อหาของother.jsp.

อย่างไรก็ตามตามคำขอ HTTP เดิมsome.jspURL ในแถบที่อยู่ของเบราว์เซอร์จะไม่เปลี่ยนแปลง นอกจากนี้แอตทริบิวต์คำขอใด ๆ ที่ตั้งค่าไว้ในคอนโทรลเลอร์ที่อยู่เบื้องหลังsome.jspother.jspจะสามารถใช้ได้ใน สิ่งนี้จะไม่เกิดขึ้นระหว่างการเปลี่ยนเส้นทางเนื่องจากโดยพื้นฐานแล้วคุณบังคับให้ไคลเอนต์สร้างคำขอ HTTP ใหม่ในที่other.jspนี้โดยจะทิ้งคำขอเดิมโดยsome.jspรวมแอตทริบิวต์ทั้งหมดไว้ด้วย


RequestDispatcherเป็นประโยชน์อย่างมากในกระบวนทัศน์ MVC และ / หรือเมื่อคุณต้องการที่จะซ่อนตัวจากการเข้าถึงโดยตรงของ JSP คุณสามารถใส่ JSP ใน/WEB-INFโฟลเดอร์และใช้Servletตัวควบคุมประมวลผลล่วงหน้าและประมวลผลคำขอภายหลัง JSPs ใน/WEB-INFโฟลเดอร์ที่ไม่สามารถเข้าถึงได้โดยตรงจาก URL แต่สามารถเข้าถึงได้โดยใช้ServletRequestDispatcher#forward()

เช่นคุณสามารถมีไฟล์ JSP ใน/WEB-INF/login.jspและLoginServletซึ่งเป็นแมปบนของurl-pattern /loginเมื่อคุณเรียกใช้http://example.com/context/loginservlet doGet()จะถูกเรียกใช้ คุณสามารถทำอะไรก็ได้ก่อนการประมวลผลที่นั่นและส่งต่อคำขอในที่สุดเช่น:

request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);

เมื่อคุณส่งแบบฟอร์มโดยปกติคุณต้องการใช้POST:

<form action="login" method="post">

วิธีนี้คือ servlet doPost()จะเรียกใช้และคุณสามารถทำการประมวลผลโพสต์ใด ๆในที่นั่น (เช่นการตรวจสอบความถูกต้องตรรกะทางธุรกิจล็อกอินผู้ใช้ ฯลฯ )

หากมีข้อผิดพลาดใด ๆ ตามปกติคุณต้องการ ส่งต่อคำขอกลับไปที่หน้าเดิมและแสดงข้อผิดพลาดที่นั่นถัดจากช่องป้อนข้อมูลเป็นต้น คุณสามารถใช้RequestDispatcherสำหรับสิ่งนี้

หากPOSTประสบความสำเร็จคุณมักจะต้องการเปลี่ยนเส้นทางเพื่อที่จะไม่ส่งคำขออีกครั้งเมื่อผู้ใช้รีเฟรชคำขอ (เช่นกด F5 หรือย้อนกลับไปในประวัติ)

User user = userDAO.find(username, password);
if (user != null) {
    request.getSession().setAttribute("user", user); // Login user.
    response.sendRedirect("home"); // Redirects to http://example.com/context/home after succesful login.
} else {
    request.setAttribute("error", "Unknown login, please try again."); // Set error.
    request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to same page so that you can display error.
}

เปลี่ยนเส้นทางจึงแนะนำให้ลูกค้าที่จะยิงใหม่GETคำขอใน URL ที่กำหนด การรีเฟรชคำขอจะรีเฟรชเฉพาะคำขอที่เปลี่ยนเส้นทางไม่ใช่คำขอเริ่มต้น วิธีนี้จะหลีกเลี่ยง "การส่งซ้ำ" และความสับสนและประสบการณ์ของผู้ใช้ที่ไม่ดี นี้เรียกว่ายังเป็นรูปแบบPOST-Redirect-GET

ดูสิ่งนี้ด้วย:


ขณะที่ผมเปลี่ยนเส้นทางจากเซิร์ฟเล็ตไปยังหน้า JSP เป็นหน้า JSP จะเต็มไปบางส่วนเช่นเดียวกับในstackoverflow.com/questions/12337624/... ฉันต้องการให้สิ่งแรกทำงานเมื่อใครก็ตามที่กดfoo.comเป็น servlet จาก servlet ฉันresponse.sendRedirect("..")ไปที่หน้า index.jsp ของเว็บไซต์ แต่นั่นทำให้พลาดไฟล์ css และข้อความบางส่วนจากหน้า jsp ซึ่งนำไปสู่การโหลดหน้าบางส่วน แต่เมื่อฉันทำให้หน้ายินดีต้อนรับของเว็บไซต์เป็น index.jsp ทุกอย่างทำงานได้ดีและโหลดหน้าเว็บเสร็จสมบูรณ์ เกิดอะไรขึ้นกับการเปลี่ยนเส้นทาง?
saplingPro

20

RequestDispatcherอินเตอร์เฟซที่ช่วยให้คุณทำฝั่งเซิร์ฟเวอร์ไปข้างหน้า / รวมในขณะที่sendRedirect()ไม่ได้เปลี่ยนเส้นทางฝั่งไคลเอ็นต์ ในการเปลี่ยนเส้นทางฝั่งไคลเอ็นต์เซิร์ฟเวอร์จะส่งรหัสสถานะ HTTP ของ302(การเปลี่ยนเส้นทางชั่วคราว) กลับซึ่งทำให้เว็บเบราว์เซอร์GETส่งคำขอHTTP ใหม่ล่าสุดสำหรับเนื้อหาที่ตำแหน่งที่เปลี่ยนเส้นทาง ในทางตรงกันข้ามเมื่อใช้RequestDispatcherอินเทอร์เฟซการรวม / ส่งต่อไปยังทรัพยากรใหม่จะได้รับการจัดการทั้งหมดที่ฝั่งเซิร์ฟเวอร์


และหลังเป็นจริงforwardไม่ใช่เปลี่ยนเส้นทาง
Adeel Ansari

5

ความแตกต่างที่สำคัญหลักระหว่างเมธอด forward () และ sendRedirect () คือในกรณีของ forward () การเปลี่ยนเส้นทางจะเกิดขึ้นที่ส่วนท้ายของเซิร์ฟเวอร์และไคลเอนต์ไม่สามารถมองเห็นได้ แต่ในกรณีของ sendRedirect () การเปลี่ยนเส้นทางจะเกิดขึ้นที่ส่วนไคลเอนต์และมองเห็นได้ ให้กับลูกค้า

ใส่คำอธิบายภาพที่นี่


2
ภาพมีค่านับพันคำ :)
Eugen Labun

4

วิธีใดวิธีหนึ่งเหล่านี้อาจ "ดีกว่า" เช่นเหมาะสมกว่าขึ้นอยู่กับสิ่งที่คุณต้องการทำ

การเปลี่ยนเส้นทางฝั่งเซิร์ฟเวอร์จะเร็วกว่าเมื่อคุณได้รับข้อมูลจากเพจอื่นโดยไม่ต้องเดินทางไปที่เบราว์เซอร์ แต่ URL ที่เห็นในเบราว์เซอร์ยังคงเป็นที่อยู่เดิมดังนั้นคุณจึงสร้างความไม่สอดคล้องกันเล็กน้อยที่นั่น

การเปลี่ยนเส้นทางฝั่งไคลเอ็นต์มีความหลากหลายมากกว่าเนื่องจากสามารถส่งคุณไปยังเซิร์ฟเวอร์ที่แตกต่างกันโดยสิ้นเชิงหรือเปลี่ยนโปรโตคอล (เช่นจาก HTTP เป็น HTTPS) หรือทั้งสองอย่าง และเบราว์เซอร์ทราบถึง URL ใหม่ แต่ต้องใช้เวลากลับไปกลับมาระหว่างเซิร์ฟเวอร์และไคลเอนต์


2
ส่วนนี้ไม่ได้กล่าวถึงอย่างเพียงพอบนเว็บ: "หรือเปลี่ยนโปรโตคอล (เช่นจาก HTTP เป็น HTTPS) หรือทั้งสองอย่าง"
Perdomoff

3

SendRedirect()จะค้นหาเนื้อหาระหว่างเซิร์ฟเวอร์ ช้าเนื่องจากต้องทำให้เบราว์เซอร์ใกล้ชิดโดยการส่ง URL ของเนื้อหา จากนั้นเบราว์เซอร์จะสร้างคำขอใหม่สำหรับเนื้อหาภายในเซิร์ฟเวอร์เดียวกันหรือในเซิร์ฟเวอร์อื่น

RquestDispatcherมีไว้สำหรับค้นหาเนื้อหาภายในเซิร์ฟเวอร์ที่ฉันคิด เป็นกระบวนการฝั่งเซิร์ฟเวอร์และเร็วกว่าเมื่อเทียบกับSendRedirect()วิธีการ แต่สิ่งที่สำคัญก็คือมันจะไม่สนิทสนมกับเบราว์เซอร์ที่เซิร์ฟเวอร์กำลังค้นหาวันที่หรือเนื้อหาที่ต้องการและจะไม่ขอให้เบราว์เซอร์เปลี่ยน URL ในแท็บ URL ดังนั้นจึงทำให้ผู้ใช้ไม่สะดวกเล็กน้อย


1

ควรใช้การเปลี่ยนเส้นทางทางเทคนิคในกรณีที่เราต้องการโอนการควบคุมไปยังโดเมนอื่นหรือเพื่อแยกงานออกจากกัน

ตัวอย่างเช่นในแอปพลิเคชันการชำระเงินเราจะดำเนินการ PaymentProcess ก่อนแล้วจึงเปลี่ยนเส้นทางไปที่ displayPaymentInfo หากไคลเอนต์รีเฟรชเบราว์เซอร์เฉพาะ displayPaymentInfo จะทำอีกครั้งและ PaymentProcess จะไม่ทำซ้ำ แต่ถ้าเราใช้ไปข้างหน้าในสถานการณ์นี้ทั้ง PaymentProcess และ displayPaymentInfo จะถูกดำเนินการใหม่ตามลำดับซึ่งอาจส่งผลให้ข้อมูลไม่สอดคล้องกัน

สำหรับสถานการณ์อื่น ๆ การส่งต่อมีประสิทธิภาพในการใช้เนื่องจากเร็วกว่า sendRedirect


0

Request Dispatcher คืออินเทอร์เฟซที่ใช้เพื่อส่งคำขอหรือการตอบกลับจากทรัพยากรบนเว็บไปยังทรัพยากรบนเว็บอื่น ประกอบด้วยสองวิธีเป็นหลัก

  1. request.forward(req,res): วิธีนี้ใช้ส่งต่อคำขอจากทรัพยากรบนเว็บหนึ่งไปยังทรัพยากรอื่น เช่นจาก servlet หนึ่งไปยัง servlet อื่นหรือจากเว็บแอปพลิเคชันหนึ่งไปยัง web appliacation อื่น

  2. response.include(req,res): วิธีนี้ใช้รวมการตอบสนองของ servlet หนึ่งไปยัง servlet อื่น

หมายเหตุ: โดยใช้ Request Dispatcher เราสามารถส่งต่อหรือรวมคำขอหรือการตอบกลับไว้ในเซิร์ฟเวอร์เดียวกันได้

request.sendRedirect(): ด้วยการใช้สิ่งนี้เราสามารถส่งต่อหรือรวมคำขอหรือการตอบสนองข้ามเซิร์ฟเวอร์ต่างๆ ในกรณีนี้ลูกค้าจะได้รับการข่มขู่ในขณะที่เปลี่ยนเส้นทางเพจ แต่ในขั้นตอนข้างต้นลูกค้าจะไม่ได้รับการข่มขู่


-1

ความแตกต่างระหว่างForward(ServletRequest request, ServletResponse response)และsendRedirect(String url)คือ

ส่งต่อ ():

  1. forward()วิธีการที่จะดำเนินการในฝั่งเซิร์ฟเวอร์
  2. คำขอถูกโอนไปยังทรัพยากรอื่นภายในเซิร์ฟเวอร์เดียวกัน
  3. ไม่ขึ้นอยู่กับโปรโตคอลการร้องขอของลูกค้าเนื่องจากไฟล์ forward ()เมธอดถูกจัดเตรียมโดย servlet container
  4. การร้องขอถูกแชร์โดยทรัพยากรเป้าหมาย
  5. วิธีนี้ใช้การโทรเพียงครั้งเดียวเท่านั้น
  6. สามารถใช้ภายในเซิร์ฟเวอร์
  7. เราไม่เห็นข้อความที่ส่งต่อ แต่เป็นแบบโปร่งใส
  8. forward()เป็นวิธีการที่เร็วกว่าsendRedirect()วิธีการ
  9. มีการประกาศในRequestDispatcherอินเทอร์เฟซ

sendRedirect ():

  1. วิธี sendRedirect () ถูกดำเนินการในฝั่งไคลเอ็นต์
  2. คำขอถูกถ่ายโอนไปยังทรัพยากรอื่นไปยังเซิร์ฟเวอร์อื่น
  3. เมธอด sendRedirect () จัดเตรียมไว้ภายใต้ HTTP ดังนั้นจึงสามารถใช้ได้กับไคลเอนต์ HTTP เท่านั้น
  4. คำขอใหม่ถูกสร้างขึ้นสำหรับทรัพยากรปลายทาง
  5. มีการเรียกใช้คำขอและการตอบกลับสองครั้ง
  6. สามารถใช้ได้ทั้งภายในและภายนอกเซิร์ฟเวอร์
  7. เราสามารถเห็นที่อยู่ที่เปลี่ยนเส้นทางมันไม่โปร่งใส
  8. เมธอด sendRedirect () ช้าลงเนื่องจากเมื่อมีการสร้างคำร้องขอใหม่อ็อบเจ็กต์คำขอเก่าจะสูญหาย
  9. มีการประกาศใน HttpServletResponse
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.