@Override
	protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
			@NonNull FilterChain filterChain) throws ServletException, IOException {
		String localNamespace = MetadataContext.LOCAL_NAMESPACE;
		String localService = MetadataContext.LOCAL_SERVICE;

		Set<Argument> arguments = rateLimitRuleArgumentResolver.getArguments(request, localNamespace, localService);

		try {
			QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI,
					localNamespace, localService, 1, arguments, request.getRequestURI());

			if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) {
				if (!Objects.isNull(polarisRateLimiterLimitedFallback)) {
					response.setStatus(polarisRateLimiterLimitedFallback.rejectHttpCode());
					String contentType = new MediaType(polarisRateLimiterLimitedFallback.mediaType(), polarisRateLimiterLimitedFallback.charset()).toString();
					response.setContentType(contentType);
					response.getWriter().write(polarisRateLimiterLimitedFallback.rejectTips());
				}
				else {
					response.setStatus(polarisRateLimitProperties.getRejectHttpCode());
					response.setContentType("text/html;charset=UTF-8");
					response.getWriter().write(rejectTips);
				}
				response.addHeader(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc());
				if (Objects.nonNull(quotaResponse.getActiveRule())) {
					try {
						String encodedActiveRuleName = URLEncoder.encode(
								quotaResponse.getActiveRuleName(), UTF_8);
						response.addHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, encodedActiveRuleName);
					}
					catch (UnsupportedEncodingException e) {
						LOG.error("Cannot encode {} for header internal-callee-activerule.",
								quotaResponse.getActiveRuleName(), e);
					}
				}
				return;
			}
			// Unirate
			if (quotaResponse.getCode() == QuotaResultCode.QuotaResultOk && quotaResponse.getWaitMs() > 0) {
				LOG.debug("The request of [{}] will waiting for {}ms.", request.getRequestURI(), quotaResponse.getWaitMs());
				Thread.sleep(quotaResponse.getWaitMs());
			}

		}
		catch (Throwable t) {
			// An exception occurs in the rate limiting API call,
			// which should not affect the call of the business process.
			LOG.error("fail to invoke getQuota, service is " + localService, t);
		}

		filterChain.doFilter(request, response);
	}
@Test
	public void testDoFilterInternal() {
		// Create mock FilterChain
		FilterChain filterChain = (servletRequest, servletResponse) -> {

		};

		// Mock request
		MockHttpServletRequest request = new MockHttpServletRequest();

		quotaCheckServletFilter.init();
		quotaCheckWithHtmlRejectTipsServletFilter.init();
		try {
			// Pass
			MetadataContext.LOCAL_SERVICE = "TestApp1";
			MockHttpServletResponse testApp1Response = new MockHttpServletResponse();
			quotaCheckServletFilter.doFilterInternal(request, testApp1Response, filterChain);

			// Unirate waiting 1000ms
			MetadataContext.LOCAL_SERVICE = "TestApp2";
			MockHttpServletResponse testApp2Response = new MockHttpServletResponse();
			long startTimestamp = System.currentTimeMillis();
			quotaCheckServletFilter.doFilterInternal(request, testApp2Response, filterChain);
			assertThat(System.currentTimeMillis() - startTimestamp).isGreaterThanOrEqualTo(1000L);

			// Rate limited
			MetadataContext.LOCAL_SERVICE = "TestApp3";
			MockHttpServletResponse testApp3Response = new MockHttpServletResponse();
			quotaCheckServletFilter.doFilterInternal(request, testApp3Response, filterChain);
			assertThat(testApp3Response.getStatus()).isEqualTo(419);
			assertThat(testApp3Response.getContentAsString()).isEqualTo("RejectRequestTips提示消息");
			assertThat(testApp3Response.getHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)).isEqualTo("MOCK_RULE");

			MockHttpServletResponse testApp3Response2 = new MockHttpServletResponse();
			quotaCheckWithHtmlRejectTipsServletFilter.doFilterInternal(request, testApp3Response2, filterChain);
			assertThat(testApp3Response2.getStatus()).isEqualTo(419);
			assertThat(testApp3Response2.getContentAsString()).isEqualTo("<h1>RejectRequestTips提示消息</h1>");

			// Exception
			MockHttpServletResponse testApp4Response = new MockHttpServletResponse();
			MetadataContext.LOCAL_SERVICE = "TestApp4";
			quotaCheckServletFilter.doFilterInternal(request, testApp4Response, filterChain);
		}
		catch (ServletException | IOException e) {
			fail("Exception encountered.", e);
		}
	}