ความแตกต่างระหว่าง / และ / * ในรูปแบบ URL การแม็พเซิร์ฟเล็ต


175

รหัสที่คุ้นเคย:

<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

ความเข้าใจของฉันอยู่ที่แผนที่/*http://host:port/context/*

แล้วไง/ล่ะ ไม่แน่ใจว่าจะแมปไปที่http://host:port/contextรากเท่านั้น ในความเป็นจริงจะยอมรับแต่ปฏิเสธhttp://host:port/context/hellohttp://host:port/context/hello.jsp

ทุกคนสามารถอธิบายวิธีการhttp://host:port/context/helloแมปได้อย่างไร

คำตอบ:


268

<url-pattern>/*</url-pattern>

/*บนเซิร์ฟเล็ตแทนที่ Servlets อื่น ๆ ทั้งหมดรวมทั้ง Servlets ทั้งหมดให้โดย servletcontainer เช่น servlet เริ่มต้นและ servlet JSP ไม่ว่าคุณจะขออะไรไฟมันจะจบลงใน servlet นั้น นี่เป็นรูปแบบ URL ที่ไม่ถูกต้องสำหรับเซิร์ฟเล็ต โดยปกติแล้วคุณต้องการใช้/*บนFilterเท่านั้น มันสามารถที่จะปล่อยให้คำขอดำเนินการต่อไปใด ๆ ของ Servlets ฟังในรูปแบบ URL FilterChain#doFilter()ที่เฉพาะเจาะจงมากขึ้นโดยการเรียก

<url-pattern>/</url-pattern>

/ไม่แทนที่เซิร์ฟเล็ตอื่น ๆ ซึ่งจะแทนที่เซิร์ฟเล็ตดีฟอลต์ที่สร้างขึ้นของ servletcontainer สำหรับคำร้องขอทั้งหมดที่ไม่ตรงกับเซิร์ฟเล็ตที่ลงทะเบียนอื่น ๆ ปกติแล้วสิ่งนี้จะถูกเรียกใช้บนสแตติกรีซอร์ส (CSS / JS / image / etc) และรายการไดเร็กทอรี servletcontainer ที่เป็นค่าดีฟอลต์ของเซิร์ฟเล็ตยังสามารถจัดการกับคำร้องขอแคช HTTP สตรีมมิ่งสื่อ (เสียง / วิดีโอ) และการดาวน์โหลดไฟล์ต่อ โดยปกติแล้วคุณไม่ต้องการแทนที่ servlet เริ่มต้นเนื่องจากคุณจะต้องดูแลงานทั้งหมดของมันซึ่งไม่ใช่เรื่องเล็กน้อย (ไลบรารียูทิลิตี้ JSF OmniFacesมีตัวอย่างโอเพ่นซอร์ส ) นี่จึงเป็นรูปแบบ URL ที่ไม่ถูกต้องสำหรับเซิร์ฟเล็ต ว่าทำไมหน้า JSP ไม่ได้ตีเซิร์ฟเล็ตนี้ก็เพราะ servletcontainer ที่คล้าย builtin JSP servlet *.jspจะถูกเรียกที่มีอยู่แล้วโดยค่าเริ่มต้นแมปในรูปแบบ

<url-pattern></url-pattern>

แล้วนอกจากนี้ยังมีรูปแบบ URL สตริงที่ว่างเปล่า สิ่งนี้จะถูกเรียกใช้เมื่อมีการร้องขอรูทบริบท สิ่งนี้แตกต่างจาก<welcome-file>วิธีการที่ไม่ได้เรียกใช้เมื่อมีการร้องขอโฟลเดอร์ย่อย นี่เป็นไปได้มากที่รูปแบบ URL ที่คุณกำลังมองหาในกรณีที่คุณต้องการ " หน้าแรก servlet " ฉันต้องยอมรับว่าฉันคาดหวังว่ารูปแบบ URL สตริงว่างเปล่า และรูปแบบ URL สแลช/ถูกกำหนดอย่างตรงไปตรงมาดังนั้นฉันสามารถเข้าใจได้ว่ามีคนเริ่มสับสนจำนวนมากในเรื่องนี้ แต่มันคือสิ่งที่มันเป็น

Front Controller

ในกรณีที่คุณจริงตั้งใจจะมี servlet ควบคุมด้านหน้าแล้วคุณต้องการที่ดีที่สุด map มันในรูปแบบ URL ที่เฉพาะเจาะจงมากขึ้นเช่น*.html, *.do, /pages/*, /app/*ฯลฯ คุณสามารถซ่อนไปรูปแบบ URL ควบคุมด้านหน้าและฝาครอบทรัพยากรคงที่ในรูปแบบ URL ที่พบบ่อย ชอบ/resources/*, /static/*ฯลฯ ด้วยความช่วยเหลือของตัวกรอง servlet ดูเพิ่มเติมวิธีการป้องกันทรัพยากรแบบคงที่จากการถูกจัดการโดย servlet ควบคุมด้านหน้าซึ่งเป็นแมปบน / * ควรสังเกตว่า Spring MVC มี servlet ทรัพยากรแบบคงที่ในตัวดังนั้นคุณจึงสามารถแมปตัวควบคุมด้านหน้าได้/หากคุณกำหนดรูปแบบ URL ทั่วไปสำหรับทรัพยากรแบบคงที่ใน Spring ดูเพิ่มเติมวิธีจัดการกับเนื้อหาคงที่ใน Spring MVC ได้อย่างไร


9
ขอบคุณ หลังจากการวิจัยบางอย่างฉันต้องการชี้แจงจุดที่ลึกซึ้ง / เขียนทับเซิร์ฟเล็ตเริ่มต้นที่เว็บเซิร์ฟเวอร์ติดตั้ง ตัวอย่างเช่น Tomcat ติดตั้ง DefaultServlet ซึ่งให้บริการทรัพยากรแบบคงที่ การใช้ / กำจัดเซิร์ฟเล็ตเริ่มต้นเป็นผลข้างเคียง (เป็นไปได้ที่ไม่พึงประสงค์)
Candy Chiu

ฉันจะไม่เรียกมันว่า "เขียนทับ" แต่ "แทนที่" มันจะมีประโยชน์ในการแทนที่เซิร์ฟเล็ตเริ่มต้นเช่นนั้น
BalusC

1
<url-pattern> </url-pattern> มีข้อผิดพลาด: ไม่ถูกต้อง <url-pattern> ในการแมปเซิร์ฟเล็ต
ผอม

ข้อความแสดงข้อผิดพลาดมาจาก Tomcat ไม่ใช่ IDE ของฉัน อย่างไรก็ตาม, ฉันใช้ Tomcat 6, ซึ่งอาจเป็นปัญหา;)
ผอม

2
@BalusC คุณช่วยบอกฉันได้ไหมว่า/**รูปแบบที่บ่งบอก?
Sajib Acharya

45

ฉันต้องการเสริมคำตอบของ BalusC ด้วยกฎการทำแผนที่และตัวอย่าง

กฎการแม็พจากข้อกำหนดคุณสมบัติ Servlet 2.5:

  1. แม็พ URL ที่ถูกต้อง
  2. แผนที่เส้นทางตัวแทน
  3. ส่วนขยายแผนที่
  4. แม็พกับเซิร์ฟเล็ตดีฟอลต์

ในตัวอย่างของเรามีสาม servlets / เป็น servlet เริ่มต้นที่เราติดตั้ง Tomcat ติดตั้งสองเซิร์ฟเล็ตเพื่อให้บริการ jsp และ jspx ดังนั้นในแผนที่http://host:port/context/hello

  1. ไม่มีการติดตั้งเซิร์ฟเล็ต URL ที่แน่นอนถัดไป
  2. ไม่มีการติดตั้งไวด์การ์ดพา ธ wildlets ถัดไป
  3. ไม่ตรงกับส่วนขยายใด ๆ ต่อไป
  4. แม็พกับดีฟอลต์เซิร์ฟเล็ตส่งคืน

แผนที่ http://host:port/context/hello.jsp

  1. ไม่มีการติดตั้งเซิร์ฟเล็ต URL ที่แน่นอนถัดไป
  2. ไม่มีการติดตั้งไวด์การ์ดพา ธ wildlets ถัดไป
  3. พบส่วนขยาย servlet ส่งคืน

25

บางทีคุณอาจจำเป็นต้องรู้ว่า URL นั้นถูกแมปด้วยเช่นกันเนื่องจากฉันประสบ404เป็นเวลาหลายชั่วโมง มีตัวจัดการการร้องขอสองชนิด และBeanNameUrlHandlerMapping SimpleUrlHandlerMappingเมื่อเรากำหนดเราจะใช้servlet-mapping SimpleUrlHandlerMappingสิ่งหนึ่งที่เราจำเป็นต้องรู้คือทั้งสองร่วมกันขนย้ายทรัพย์สินส่วนกลางที่เรียกว่าที่เริ่มต้นที่alwaysUseFullPathfalse

falseนี่หมายความว่า Spring จะไม่ใช้เส้นทางแบบเต็มในการแมป URL ไปยังตัวควบคุม มันหมายความว่าอะไร? มันหมายถึงเมื่อคุณกำหนดservlet-mapping:

<servlet-mapping>
    <servlet-name>viewServlet</servlet-name>
    <url-pattern>/perfix/*</url-pattern>
</servlet-mapping>

ตัวจัดการจะใช้ชิ้น*ส่วนเพื่อค้นหาตัวควบคุม ตัวอย่างเช่นตัวควบคุมต่อไปนี้จะพบ404ข้อผิดพลาดเมื่อคุณร้องขอโดยใช้/perfix/api/feature/doSomething

@Controller()
@RequestMapping("/perfix/api/feature")
public class MyController {
    @RequestMapping(value = "/doSomething", method = RequestMethod.GET) 
    @ResponseBody
    public String doSomething(HttpServletRequest request) {
        ....
    }
}

มันเป็นคู่ที่สมบูรณ์แบบใช่มั้ย 404แต่ทำไม ดังกล่าวก่อนหน้านี้ค่าเริ่มต้นของalwaysUseFullPathเป็นเท็จซึ่งหมายถึงในคำขอของคุณเพียง/api/feature/doSomethingใช้ในการค้นหาตัวควบคุมที่เกี่ยวข้อง แต่ไม่มีตัวควบคุมใส่ใจเกี่ยวกับเส้นทางนั้น คุณจำเป็นต้องมีการเปลี่ยนแปลงอย่างใดอย่างหนึ่ง URL ของคุณไป/perfix/perfix/api/feature/doSomethingหรือลบจากฐานperfix MyController@RequestingMapping


8

ฉันคิดว่าคำตอบของ Candy นั้นถูกต้องที่สุด มีส่วนเล็ก ๆ ที่ฉันคิดเป็นอย่างอื่น

ในการแม็พโฮสต์: port / context / hello.jsp

  1. ไม่มีการติดตั้งเซิร์ฟเล็ต URL ที่แน่นอนถัดไป
  2. พบสัญลักษณ์เส้นทาง servletsคืน

ฉันเชื่อว่าทำไม "/ *" ไม่ตรงกับโฮสต์: พอร์ต / บริบท / hello เพราะถือว่า "/ hello" เป็นเส้นทางแทนไฟล์ (เนื่องจากไม่มีส่วนขยาย)


2

ความแตกต่างที่สำคัญระหว่าง/*และ/คือ servlet ที่มีการแมป/*จะถูกเลือกก่อน servlet ใด ๆ ที่มีการแมปส่วนขยาย (เช่น*.html) ในขณะที่ servlet ที่มีการแมป/จะถูกเลือกหลังจากพิจารณาการแม็พส่วนขยายแล้วเท่านั้น (และจะใช้สำหรับคำขอใด ๆ ไม่ตรงกับสิ่งอื่น --- เป็น "default servlet")

โดยเฉพาะอย่างยิ่งการ/*ทำแผนที่จะถูกเลือกเสมอก่อนการ/ทำแผนที่ มีทั้งป้องกันการร้องขอใด ๆ จากการเข้าถึงเซิร์ฟเล็ตเริ่มต้นของภาชนะ

จะถูกเลือกอย่างใดอย่างหนึ่งหลังจากการแมปเซิร์ฟเล็ตซึ่งเป็นการจับคู่ที่ตรงกัน (เช่น/foo/bar) และการแมปพา ธ ที่ยาวกว่า/*(เช่น/foo/*) โปรดทราบว่าการจับคู่สตริงว่างนั้นเป็นการจับคู่ที่ตรงกันสำหรับรูทบริบท ( http://host:port/context/)

ดูบทที่ 12 ของข้อมูลจำเพาะ Java Servlet ที่มีอยู่ในเวอร์ชัน 3.1 ที่http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.