นี่คือโพสต์ที่แปลด้วย AI
[Spring] Filter, Interceptor, Argument Resolver คืออะไร?
- ภาษาที่เขียน: ภาษาเกาหลี
- •
- ประเทศอ้างอิง: ทุกประเทศ
- •
- เทคโนโลยีสารสนเทศ
เลือกภาษา
สรุปโดย AI ของ durumis
- ตัวกรองเป็นฟังก์ชันมาตรฐาน J2EE ที่ให้ความสามารถในการประมวลผลงานเพิ่มเติมสำหรับทุก ๆ คำขอที่ตรงกับรูปแบบ URL ก่อน หรือหลังจากที่คำขอถูกส่งไปยังดิสแพตเชอร์เซอร์วิล็ต ตัวกรองทำงานในเว็บคอนเทนเนอร์ ในขณะที่อินเทอร์เซปเตอร์เป็นเทคโนโลยีที่ สปริงจัดเตรียมไว้ ซึ่งให้ความสามารถในการอ้างอิงหรือประมวลผลคำขอและการตอบสนองก่อนหรือหลังจากที่ดิสแพตเชอร์ เซอร์วิล็ตเรียกคอนโทรลเลอร์ อินเทอร์เซปเตอร์ทำงานในสปริงคอนเท็กซ์
- Argument Resolver ช่วยสร้างออบเจ็กต์ที่ต้องการจากค่าที่ส่งมาในคำขอเมื่อคำขอใด ๆ เข้าสู่คอนโทรลเลอร์
- ตัวกรองและอินเทอร์เซปเตอร์มีความแตกต่างกันในแง่ของการทำงานในสปริงคอนเทนเนอร์หรือเว็บคอนเทนเนอร์ การประมวลผล คำขอตามดิสแพตเชอร์เซอร์วิล็ตหรือคอนโทรลเลอร์ และ Argument Resolver ทำงานหลังอินเทอร์เซปเตอร์และคืนค่าออบเจ็กต์ เฉพาะเจาะจง
อะไรคือตัวกรอง (Filter)?
ตัวกรองเป็นฟังก์ชันมาตรฐาน J2EE ที่ให้ความสามารถในการประมวลผลงานเพิ่มเติมสำหรับทุกคำขอที่ตรงกับรูปแบบ url ก่อน/หลังการส่งคำขอไปยัง Dispatcher Servlet หมายความว่าถูกจัดการโดยเว็บคอนเทนเนอร์ เช่น Tomcat ไม่ใช่สปริงคอนเทนเนอร์ ดังนั้นจึงประมวลผลคำขอ ก่อนที่จะไปถึง Dispatcher Servlet
การใช้งานตัวกรอง (Filter)
เพื่อเพิ่มตัวกรอง คุณต้องใช้อินเทอร์เฟซ Filter ของ javax.servlet ซึ่งมีเมธอด 3 เมธอด ดังต่อไปนี้
- เมธอด init
- เป็นเมธอดสำหรับการเริ่มต้นวัตถุตัวกรองและเพิ่มลงในบริการ เว็บคอนเทนเนอร์จะเรียกเมธอด init หนึ่งครั้งเพื่อเริ่มต้นวัตถุตัวกรอง จากนั้นคำขอต่อๆ ไปจะถูกประมวลผลผ่านเมธอด doFilter()
- เมธอด doFilter
- เป็นเมธอดที่ถูกเรียกใช้โดยเว็บคอนเทนเนอร์ก่อนที่ทุกคำขอ HTTP ที่ตรงกับรูปแบบ url จะถูกส่งไปยัง Dispatcher Servlet และถูกเรียกใช้โดยเว็บคอนเทนเนอร์ก่อนที่ Dispatcher Servlet จะส่งการตอบสนอง HTTP ไปยังไคลเอ็นต์
พารามิเตอร์ของ doFilter() มี FilterChain ซึ่ง chain.doFilter() จะส่งคำขอไปยังเป้าหมายถัดไป เราสามารถแทรกกระบวนการประมวลผลที่เราต้องการก่อน/หลัง chain.doFilter() เพื่อดำเนินการประมวลผลที่ต้องการ
- เป็นเมธอดที่ถูกเรียกใช้โดยเว็บคอนเทนเนอร์ก่อนที่ทุกคำขอ HTTP ที่ตรงกับรูปแบบ url จะถูกส่งไปยัง Dispatcher Servlet และถูกเรียกใช้โดยเว็บคอนเทนเนอร์ก่อนที่ Dispatcher Servlet จะส่งการตอบสนอง HTTP ไปยังไคลเอ็นต์
- เมธอด destory
- เป็นเมธอดสำหรับการลบวัตถุตัวกรองออกจากบริการและส่งคืนทรัพยากรที่ถูกใช้ เป็นเมธอดที่ถูกเรียกใช้โดยเว็บคอนเทนเนอร์เพียงครั้งเดียว หลังจากนั้นจะไม่ได้รับการประมวลผลโดย doFilter() อีกต่อไป
ตัวอย่างรหัส - ข้อมูลจำเพาะของ Servlet
@WebFilter("/*")
public class dolphagoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
//การประมวลผลเบื้องต้นที่นี่
request.setCharacterEncoding("UTF-8");
System.out.println("doFilter() ก่อน...");
filterChain.doFilter(request, response);
//การประมวลผลหลังการประมวลผลที่นี่
System.out.println("doFilter() หลัง...");
}
@Override
public void destroy() { }
ตัวอย่างรหัส - @Component
@Order(1)
@Component
public class CustomFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override
public void destroy() { }
- @Component: สามารถลงทะเบียน Filter เป็น Bean ของ Spring ได้
- @Order: สามารถระบุลำดับได้ หากมีตัวกรองหลายตัว
- หากลงทะเบียนตัวกรองที่ตรงกับข้อมูลจำเพาะของ Servlet เป็น Bean ของ Spring จะสามารถใช้ Bean อื่นๆ ที่ตรงกับข้อมูลจำเพาะของ Spring ได้
ตัวอย่างรหัส - @Configuration
@Configuration
public class CustomRegistrationBean {
@Bean
public FilterRegistrationBean customFilterBean() {
FilterRegistrationBean registration = new FilterRegistrationBean<>();
registration.setFilter(new CustomFilter());
registration.setOrder(1);
registration.addUrlPatterns("/api/*");
return registration;
}
หากคุณต้องการให้ตัวกรองทำงานเฉพาะกับ URI เฉพาะ คุณสามารถลงทะเบียนตัวกรองเป็น Bean ของ Spring โดยใช้ FilterRegistrationBean
การใช้งานตัวกรอง (Filter)
มักจะรับผิดชอบในการตรวจสอบและประมวลผลพารามิเตอร์ของคำขอเอง
- งานทั่วไปที่เกี่ยวข้องกับความปลอดภัย
- เนื่องจากตัวกรองทำงานในเว็บคอนเทนเนอร์ ดังนั้นจึงสามารถตรวจสอบความปลอดภัย (XSS, การป้องกัน CSRF ฯลฯ) และบล็อกคำขอที่ไม่ถูกต้องได้ สิ่งนี้สามารถเพิ่มความปลอดภัยได้มากขึ้น เนื่องจากคำขอจะไม่ถูกส่งไปยังสปริงคอนเทนเนอร์
- การบันทึกสำหรับทุกคำขอ
- การบีบอัดรูปภาพ/ข้อมูล และการเข้ารหัสสตริง
- ตัวกรองได้ใช้ฟังก์ชันทั่วไปในแอปพลิเคชันเว็บ เช่น การบีบอัดรูปภาพหรือข้อมูล และการเข้ารหัสสตริง
- การปรับแต่ง ServletRequest
- HttpServletRequest สามารถอ่านเนื้อหาของ Body ได้เพียงครั้งเดียว ดังนั้น Filter หรือ Interceptor ไม่สามารถอ่าน Body ได้ เราสามารถสร้าง ServletRequest ที่กำหนดเองเพื่อบันทึก Body
ตัวตัดรับ (Interceptor)
อะไรคือตัวตัดรับ (Interceptor)?
ตัวตัดรับ (Interceptor) ไม่เหมือนกับตัวกรอง (Filter) ซึ่งเป็นข้อมูลจำเพาะมาตรฐาน J2EE เป็นเทคโนโลยีที่สปริงให้บริการ และสามารถอ้างอิงหรือประมวลผลคำขอและการตอบสนองก่อน/หลัง Dispatcher Servlet เรียกคอนโทรลเลอร์ หมายความว่าตัวตัดรับทำงานในสปริงคอนเท็กซ์ ต่างจากตัวกรองที่ทำงานในเว็บคอนเทนเนอร์
Dispatcher Servlet จะขอให้แมปตัวจัดการเพื่อค้นหาคอนโทรลเลอร์ที่เหมาะสม ซึ่งจะส่งคืนสายโซ่การดำเนินการ (HandlerExecutionChain) ดังนั้น หากสายโซ่การดำเนินการนี้มีตัวตัดรับที่ลงทะเบียนไว้มากกว่า 1 รายการ จะดำเนินการตัวตัดรับตามลำดับก่อนที่จะเรียกใช้คอนโทรลเลอร์ และหากไม่มีตัวตัดรับ จะเรียกใช้คอนโทรลเลอร์โดยตรง
การใช้งานตัวตัดรับ (Interceptor)
เพื่อเพิ่มตัวตัดรับ คุณต้องใช้อินเทอร์เฟซ HandlerInterceptor ของ org.springframework.web.servlet ซึ่งมีเมธอด 3 เมธอด ดังต่อไปนี้
- เมธอด preHandle
- เมธอด preHandle จะถูกเรียกใช้ก่อนที่จะเรียกใช้คอนโทรลเลอร์ ดังนั้นจึงสามารถใช้สำหรับงานประมวลผลเบื้องต้น ก่อนคอนโทรลเลอร์ หรือเพื่อประมวลผลหรือเพิ่มข้อมูลคำขอ
- พารามิเตอร์ handler ในเมธอด preHandle คือวัตถุที่เป็นนามธรรมของข้อมูลของเมธอดที่มี @RequestMapping
- ประเภทผลลัพธ์ของเมธอด preHandle คือ boolean หากผลลัพธ์เป็น true จะดำเนินการต่อในขั้นตอนถัดไป แต่หากเป็น false งานจะถูกหยุด และงานที่ตามมา (ตัวตัดรับถัดไปหรือคอนโทรลเลอร์) จะไม่ถูกดำเนินการ
- เมธอด postHandle
- เมธอด postHandle จะถูกเรียกใช้หลังจากที่คอนโทรลเลอร์ถูกเรียกใช้ ดังนั้นจึงสามารถใช้สำหรับงานประมวลผลหลังการประมวลผล หลังคอนโทรลเลอร์
- เมธอด afterCompletion
- เมธอด afterCompletion จะถูกเรียกใช้หลังจากที่งานทั้งหมดเสร็จสิ้น รวมถึงการสร้างผลลัพธ์สุดท้ายจากทุกมุมมอง
ตัวอย่างรหัส
@Component
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomInterceptor());
registry.addInterceptor(new LoggingInterceptor());
}
- ลงทะเบียนตัวตัดรับที่สร้างขึ้นเป็น Bean
- ลงทะเบียนตัวตัดรับที่สร้างขึ้นในเมธอด addInterceptors() ของอินเทอร์เฟซ WebMvcConfigurer
- ตัวตัดรับจะทำงานตามลำดับที่ลงทะเบียนไว้ใน InterceptorRegistry
การใช้งานตัวตัดรับ (Interceptor)
มักจะรับผิดชอบในการประมวลผลความถูกต้องของข้อมูลคำขอโดยใช้ตรรกะบริการ
- งานทั่วไป เช่น การรับรองความถูกต้อง/การอนุญาต
- ตัวอย่างเช่น การรับรองความถูกต้องหรือการอนุญาต ซึ่งเป็นงานที่เกี่ยวข้องกับคำขอของไคลเอ็นต์ สามารถตรวจสอบได้ก่อนที่จะส่งไปยังคอนโทรลเลอร์
- การบันทึกสำหรับการเรียกใช้ API
- สามารถบันทึกข้อมูลของไคลเอ็นต์ผ่านวัตถุ HttpServletRequest และ HttpServletResponse ที่ได้รับ
- การประมวลผลข้อมูลที่จะส่งไปยัง Controller
- สามารถประมวลผลวัตถุ HttpServletRequest และ HttpServletResponse ที่ได้รับ และส่งไปยังคอนโทรลเลอร์
- เลียนแบบ AOP
- สามารถระบุข้อมูลเพิ่มเติม เช่น ลายเซ็นของเมธอดที่จะเรียกใช้ผ่าน HandlerMethod ซึ่งเป็นพารามิเตอร์ที่ 3 ของเมธอด preHandle() เพื่อตัดสินใจว่าจะดำเนินการตรรกะหรือไม่
ตัวกรอง (Filter) vs ตัวตัดรับ (Interceptor)
- ตัวกรองจะทำงานในเว็บคอนเท็กซ์ และตัวตัดรับจะทำงานในสปริงคอนเท็กซ์ ดังนั้นจุดเวลาในการดำเนินการจึงแตกต่างกัน
- ตัวกรองสามารถจัดการก่อน/หลัง Dispatcher Servlet และตัวตัดรับสามารถจัดการก่อน/หลังคอนโทรลเลอร์ได้
- ตัวกรองเหมาะสำหรับใช้ในกรณีที่ต้องประมวลผลงานทั่วไปที่ไม่เกี่ยวข้องกับสปริง ตรวจสอบพารามิเตอร์อินพุตเอง หรือใช้ ServletRequest แทน HttpServletRequest
- ตัวตัดรับเหมาะสำหรับใช้ในกรณีที่ต้องประมวลผลงานทั่วไปที่เกี่ยวข้องกับคำขอของไคลเอ็นต์ที่เข้าสู่สปริง หรือเมื่อต้องการผสมตรรกะบริการ
- ตัวตัดรับสามารถใช้ @ControllerAdvice และ @ExceptionHandler เพื่อจัดการข้อยกเว้น แต่ตัวกรองไม่สามารถใช้เพื่อจัดการข้อยกเว้นได้
- ตัวกรองมักจะจัดการข้อยกเว้นที่เกิดขึ้นในขั้นตอนนั้นโดยตรงโดยการห่อ doFilter() รอบๆ ด้วยบล็อก try~catch
ตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver)
ตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver) คืออะไร?
ตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver) สามารถสร้างวัตถุที่ต้องการจากค่าที่ส่งมาพร้อมกับคำขอไปยังคอนโทรลเลอร์ได้อย่างอ้อม
การใช้งานตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver)
สมมติว่าคำขอมาพร้อมกับโทเค็น JWT ตัวอย่างเช่น เราจำเป็นต้องตรวจสอบว่าโทเค็นนี้เป็นโทเค็นที่ถูกต้องหรือไม่ และดึง id ที่เก็บอยู่ในโทเค็นออก แล้วสร้างเป็นวัตถุผู้ใช้ที่เข้าสู่ระบบ
ในกรณีนี้ หากไม่ใช้ตัวแก้ไขอาร์กิวเมนต์ คุณจะต้องใช้วิธีการตรวจสอบโทเค็นและแปลงเป็นวัตถุผู้ใช้ที่เข้าสู่ระบบในทุกคอนโทรลเลอร์ ซึ่งจะทำให้เกิดรหัสซ้ำซ้อนในคอนโทรลเลอร์ที่จำเป็นต้องตรวจสอบผู้ใช้ และเพิ่มความรับผิดชอบของคอนโทรลเลอร์ ตัวแก้ไขอาร์กิวเมนต์ สามารถแก้ไขปัญหานี้ได้
การใช้งานตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver)
ตัวแก้ไขอาร์กิวเมนต์สามารถใช้งานได้โดยการใช้อินเทอร์เฟซ HandlerMethodArgumentResolver และอินเทอร์เฟซนี้จะระบุให้ใช้เมธอดสองเมธอดดังต่อไปนี้
boolean supportsParameter(MethodParameter parameter);
@Nullable
- เมธอด supportsParameter
- สร้างและแนบคำอธิบายประกอบเฉพาะกับพารามิเตอร์ของเมธอดที่ต้องการให้ตัวแก้ไขอาร์กิวเมนต์ทำงาน เมธอด supportsParameter() จะตรวจสอบว่าเมธอดที่ร้องขอมีคำอธิบายประกอบที่ต้องการหรือไม่ และส่งคืน true หากมีคำอธิบายประกอบที่ต้องการ
- เมธอด resolveArgument
- หากได้รับ true จาก supportsParameter หมายความว่ามีเมธอดที่มีคำอธิบายประกอบเฉพาะ เป็นเมธอดที่ผูกข้อมูลกับพารามิเตอร์ให้เป็นรูปแบบที่ต้องการและส่งคืน
นี่คือวิธีการใช้งานตัวแก้ไขอาร์กิวเมนต์ในคอนโทรลเลอร์
@GetMapping("/me")
public ResponseEntity findMemberOfMine(@AuthenticationPrincipal LoginMember loginMember) {
MemberResponse memberResponse = memberService.findMember(loginMember.getId());
return ResponseEntity.ok().body(memberResponse);
ความแตกต่างระหว่างตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver) และตัวตัดรับ (Interceptor)
- ตัวแก้ไขอาร์กิวเมนต์จะทำงานหลังจากตัวตัดรับ และจะส่งคืนวัตถุที่ต้องการจากค่าที่ส่งมาพร้อมกับคำขอไปยังคอนโทรลเลอร์
- ในทางกลับกัน ตัวตัดรับจะสกัดกั้นคำขอ ก่อนที่จะเรียกใช้คอนโทรลเลอร์จริง และไม่สามารถส่งคืนวัตถุใดๆ จะมีเฉพาะประเภทผลลัพธ์ boolean หรือ void เท่านั้น
แหล่งที่มา
- https://mangkyu.tistory.com/173
- https://junhyunny.github.io/spring-boot/filter-interceptor-and-aop/
- https://supawer0728.github.io/2018/04/04/spring-filter-interceptor/
- https://tecoble.techcourse.co.kr/post/2021-05-24-spring-interceptor/
- https://baeldung-cn.com/spring-mvc-handlerinterceptor-vs-filter
- https://www.baeldung.com/spring-boot-add-filter
คำถามที่คาดหวังในการสัมภาษณ์และคำตอบ
ตัวกรองคืออะไร?
ตัวกรองเป็นฟังก์ชันที่ให้ความสามารถในการประมวลผลงานเพิ่มเติมสำหรับทุกคำขอที่ตรงกับรูปแบบ url ก่อน/หลังการส่งคำขอไปยัง Dispatcher Servlet และทำงานในระดับ Servlet Container
เวลาใดที่ควรใช้ตัวกรอง?
ตัวกรองสามารถใช้สำหรับประมวลผลงานทั่วไปที่ไม่เกี่ยวข้องกับสปริงได้ หรือใช้เมื่อต้องการตรวจสอบพารามิเตอร์คำขอ
ตัวอย่างเช่น งานทั่วไปที่เกี่ยวข้องกับความปลอดภัย การบันทึกสำหรับทุกคำขอ การบีบอัดรูปภาพ/ข้อมูล และการเข้ารหัสสตริง และการปรับแต่ง ServletRequest
ตัวตัดรับคืออะไร?
ตัวตัดรับสามารถอ้างอิงหรือประมวลผลคำขอและการตอบสนองก่อน/หลัง Dispatcher Servlet เรียกคอนโทรลเลอร์ และทำงานในระดับ Spring Container
เวลาใดที่ควรใช้ตัวตัดรับ?
ตัวตัดรับสามารถใช้สำหรับประมวลผลงานทั่วไปที่เกี่ยวข้องกับคำขอของไคลเอ็นต์ หรือเมื่อต้องการตรวจสอบและใช้ตรรกะบริการ
ตัวอย่างเช่น งานทั่วไป เช่น การรับรองความถูกต้อง/การอนุญาต การบันทึกสำหรับการเรียกใช้ API และการประมวลผลข้อมูลที่จะส่งไปยัง Controller
ความแตกต่างระหว่างตัวกรองและตัวตัดรับคืออะไร?
ตัวกรองจะทำงานในระดับ Servlet Container และตัวตัดรับจะทำงานในระดับ Spring Container
ตัวกรองสามารถจัดการก่อน/หลัง Dispatcher Servlet และตัวตัดรับสามารถจัดการก่อน/หลังคอนโทรลเลอร์ได้
ดังนั้น ตัวกรองจึงเหมาะสำหรับใช้ในกรณีที่ต้องประมวลผลงานทั่วไปที่ไม่เกี่ยวข้องกับสปริง และตัวตัดรับจึงเหมาะสำหรับใช้ในกรณีที่ต้องประมวลผลงานทั่วไปที่เกี่ยวข้องกับคำขอของไคลเอ็นต์
ตัวแก้ไขอาร์กิวเมนต์คืออะไร?
ตัวแก้ไขอาร์กิวเมนต์สามารถสร้างวัตถุที่ต้องการจากค่าที่ส่งมาพร้อมกับคำขอไปยังคอนโทรลเลอร์ได้อย่างอ้อม
เวลาใดที่ควรใช้ตัวแก้ไขอาร์กิวเมนต์?
ตัวอย่างเช่น เมื่อคำขอมาพร้อมกับโทเค็น JWT เราจำเป็นต้องตรวจสอบว่าโทเค็นนี้เป็นโทเค็นที่ถูกต้องหรือไม่ และดึง id ที่เก็บอยู่ในโทเค็นออก แล้วสร้างเป็นวัตถุ LoginMember
ความแตกต่างระหว่างตัวตัดรับและตัวแก้ไขอาร์กิวเมนต์คืออะไร?
ตัวแก้ไขอาร์กิวเมนต์จะส่งคืนวัตถุที่ต้องการจากค่าที่ส่งมาพร้อมกับคำขอไปยังคอนโทรลเลอร์ ในขณะที่ตัวตัดรับไม่สามารถส่งคืนวัตถุใดๆ และตัวแก้ไขอาร์กิวเมนต์จะทำงานหลังจากตัวตัดรับ