1. 程式人生 > >Spring mvc 從一個http請求分析DispatcherServlet的工作過程

Spring mvc 從一個http請求分析DispatcherServlet的工作過程

開發工具 Intellij IDEA 

目標、除錯 請求http://localhost:8080/coffee/helloworld

 <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/coffee</url-pattern>
    </servlet-mapping>
url-pattern 攔截所有的/coffee開頭的請求
@Controller
@RequestMapping("coffee")
public class HelloControler{
	@RequestMapping("helloworld")
	public @ResponseBody String helloWorld() {
		System.out.println("xxx");
		return "hello 222 world";
	}
}

<pre style="font-family: 宋體; font-size: 12pt; background-color: rgb(255, 255, 255);"><pre name="code" class="java">/**
 * Delegate GET requests to processRequest/doService.
 * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
 * with a {@code NoBodyResponse} that just captures the content length.
 * @see #doService
 * @see #doHead
 */
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   processRequest(request, response);
} 
 org.springframework.web.servlet.FrameworkServlet

/**
	 * Process this request, publishing an event regardless of the outcome.
	 * <p>The actual event handling is performed by the abstract
	 * {@link #doService} template method.
	 */
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;

		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContext localeContext = buildLocaleContext(request);

		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

		initContextHolders(request, localeContext, requestAttributes);

		try {
			doService(request, response);//******* doService *********//
		}
		catch (ServletException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (IOException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (Throwable ex) {
			failureCause = ex;
			throw new NestedServletException("Request processing failed", ex);
		}

		finally {
			resetContextHolders(request, previousLocaleContext, previousAttributes);
			if (requestAttributes != null) {
				requestAttributes.requestCompleted();
			}

			if (logger.isDebugEnabled()) {
				if (failureCause != null) {
					this.logger.debug("Could not complete request", failureCause);
				}
				else {
					if (asyncManager.isConcurrentHandlingStarted()) {
						logger.debug("Leaving response open for concurrent processing");
					}
					else {
						this.logger.debug("Successfully completed request");
					}
				}
			}

			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}

接著看一下 DispatcherServlet的方法
/**
	 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
	 * for the actual dispatching.
	 */
	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
					" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
		}

		// Keep a snapshot of the request attributes in case of an include,
		// to be able to restore the original attributes after the include.
		Map<String, Object> attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap<String, Object>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}

		// Make framework objects available to handlers and view objects.
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

		FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
		if (inputFlashMap != null) {
			request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
		}
		request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
		request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

		try {
			doDispatch(request, response);//********************************///
		}
		finally {
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// Restore the original attribute snapshot, in case of an include.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}
然後看一下 最關鍵的方法
/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);
// **********************************根據request查詢mappedHandler 也就是一個Controller
				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}
看一下Spring如何匹配url 然後查詢對應的Controller
/**
	 * Return the HandlerExecutionChain for this request.
	 * <p>Tries all handler mappings in order.
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
	 */
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}
private List<HandlerMapping> handlerMappings;

handlerMappings 是包含倆元素
BeanNameUrlHandlerMapping 
DefaultAnnotationHandlerMapping
package org.springframework.web.servlet.handler;
/**
	 * Look up a handler for the given request, falling back to the default
	 * handler if no specific one is found.
	 * @param request current HTTP request
	 * @return the corresponding handler instance, or the default handler
	 * @see #getHandlerInternal
	 */
	@Override
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = getApplicationContext().getBean(handlerName);
		}

		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		return executionChain;
	}

package org.springframework.web.servlet.handler;
/**
	 * Look up a handler for the URL path of the given request.
	 * @param request current HTTP request
	 * @return the handler instance, or {@code null} if none found
	 */
	@Override
	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);//coffee/helloworld *** 往下看
		Object handler = lookupHandler(lookupPath, request);
		if (handler == null) {
			// We need to care for the default handler directly, since we need to
			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = getApplicationContext().getBean(handlerName);
				}
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
			}
		}
		if (handler != null && logger.isDebugEnabled()) {
			logger.debug("Mapping [" + lookupPath + "] to " + handler);
		}
		else if (handler == null && logger.isTraceEnabled()) {
			logger.trace("No handler mapping found for [" + lookupPath + "]");
		}
		return handler;
	}

package org.springframework.web.util;
class UrlPathHelper
 public String getLookupPathForRequest(HttpServletRequest request) {
        if(this.alwaysUseFullPath) {
            return this.getPathWithinApplication(request);
        } else {
            String rest = this.getPathWithinServletMapping(request);//執行結果 --> ""
            return !"".equals(rest)?rest:this.getPathWithinApplication(request);//執行getpathWithApplication 返回 /coffee/helloworld
        }
    }
上面的方法執行的是else
public String getPathWithinServletMapping(HttpServletRequest request) {
        String pathWithinApp = this.getPathWithinApplication(request);//coffee/helloworld  ******往下看
        String servletPath = this.getServletPath(request);<span style="font-family: 宋體;">//coffee/helloworld  </span><span style="font-family: 宋體;">******往下看</span>
        String sanitizedPathWithinApp = this.getSanitizedPath(pathWithinApp);
        String path;
        if(servletPath.contains(sanitizedPathWithinApp)) {
            path = this.getRemainingPath(sanitizedPathWithinApp, servletPath, false); //結果 ""
        } else {
            path = this.getRemainingPath(pathWithinApp, servletPath, false);
        }

        if(path != null) {
            return path; // 返回 ""
        } else {
            String pathInfo = request.getPathInfo();
            if(pathInfo != null) {
                return pathInfo;
            } else {
                if(!this.urlDecode) {
                    path = this.getRemainingPath(this.decodeInternal(request, pathWithinApp), servletPath, false);
                    if(path != null) {
                        return pathWithinApp;
                    }
                }

                return servletPath;
            }
        }
    }

public String getPathWithinApplication(HttpServletRequest request) {
        String contextPath = this.getContextPath(request);// ""
        String requestUri = this.getRequestUri(request);//coffee/helloworld
        String path = this.getRemainingPath(requestUri, contextPath, true);//coffee/helloworld
        return path != null?(StringUtils.hasText(path)?path:"/"):requestUri;//coffee/helloworld
    }

 public String getContextPath(HttpServletRequest request) {
        String contextPath = (String)request.getAttribute("javax.servlet.include.context_path");
        if(contextPath == null) {
            contextPath = request.getContextPath();
        }

        if("/".equals(contextPath)) {///*****注意一下這個方法如果
            contextPath = "";
        }

        return this.decodeRequestString(request, contextPath);
    }

public String getServletPath(HttpServletRequest request) {
        String servletPath = (String)request.getAttribute("javax.servlet.include.servlet_path");
        if(servletPath == null) {
            servletPath = request.getServletPath();//*******/coffee/helloworld
        }

        if(servletPath.length() > 1 && servletPath.endsWith("/") && this.shouldRemoveTrailingServletPathSlash(request)) {
            servletPath = servletPath.substring(0, servletPath.length() - 1);
        }

        return servletPath;
    }


/**
	 * Look up a handler instance for the given URL path.
	 * <p>Supports direct matches, e.g. a registered "/test" matches "/test",
	 * and various Ant-style pattern matches, e.g. a registered "/t*" matches
	 * both "/test" and "/team". For details, see the AntPathMatcher class.
	 * <p>Looks for the most exact pattern, where most exact is defined as
	 * the longest path pattern.
	 * @param urlPath URL the bean is mapped to
	 * @param request current HTTP request (to expose the path within the mapping to)
	 * @return the associated handler instance, or {@code null} if not found
	 * @see #exposePathWithinMapping
	 * @see org.springframework.util.AntPathMatcher
	 */
	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match? *************************************下面一行程式碼是真正查詢Controller的方法
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}
		// Pattern match?
		List<String> matchingPatterns = new ArrayList<String>();
		for (String registeredPattern : this.handlerMap.keySet()) {
			if (getPathMatcher().match(registeredPattern, urlPath)) {
				matchingPatterns.add(registeredPattern);
			}
			else if (useTrailingSlashMatch()) {
				if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
					matchingPatterns.add(registeredPattern +"/");
				}
			}
		}
		String bestPatternMatch = null;
		Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
		if (!matchingPatterns.isEmpty()) {
			Collections.sort(matchingPatterns, patternComparator);
			if (logger.isDebugEnabled()) {
				logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
			}
			bestPatternMatch = matchingPatterns.get(0);
		}
		if (bestPatternMatch != null) {
			handler = this.handlerMap.get(bestPatternMatch);
			if (handler == null) {
				Assert.isTrue(bestPatternMatch.endsWith("/"));
				handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
			}
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);

			// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
			// for all of them
			Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
			for (String matchingPattern : matchingPatterns) {
				if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
					Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
					Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
					uriTemplateVariables.putAll(decodedVars);
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
			}
			return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
		}
		// No handler found...
		return null;
	}


相關推薦

Spring mvc 一個http請求分析DispatcherServlet工作過程

開發工具 Intellij IDEA  目標、除錯 請求http://localhost:8080/coffee/helloworld <servlet> <servlet-name>dispatcher</servlet-

基於Spring MVC框架的Http流程分析

一、問題提出 我們可以方便的利用Spring MVC進行業務開發,請求的大部分工作都被框架和容器封裝,使得我們只需要做很少量的

Spring MVC 處理一個請求的流程分析

Spring MVC是Spring系列框架中使用頻率最高的部分。不管是Spring Boot還是傳統的Spring專案,只要是Web專案都會使用到Spring MVC部分。因此程式設計師一定要熟練掌握MVC部分。本篇部落格簡要分析Spring MVC處理一個請求的流程。 一個請求從客戶端發出到達伺服器,然後

Spring MVC @RestController接收POST請求,用Map接收

@requestbody 微服務 springboot springmvc背景脫離傳統項目,使用微服務集群開發後。RestFul風格勢在必行,所以,本篇文章針對使用restful風格的編寫人員。主題restful post請求提交的參數用什麽接收?關鍵字Map、Entity內容1、首先,傳統的接收使用Http

spring mvc@ResponseBody取到json發現中文亂碼

tab reat builder attr cover proc first hresult acc   問題背景:如題。   問題定位:代碼跟蹤,從源頭入手,一步一步跟進,直到設置中文編碼的地方。   問題代碼: /** * 獲取單個測試樁接口內容

Spring MVC Controller向頁面傳值的方式

用戶 () 傳參數 control let att model enter 設定 Spring MVC 從 Controller向頁面傳值的方式 在實際開發中,Controller取得數據(可以在Controller中處理,當然也可以來源於業務邏輯層),傳給頁面,常用的方

Spring MVC - 02 RequestMapping對映請求

使用 @RequestMapping 對映請求 1.SpringMVC 使用@RequestMapping 註解為 控制器 指定可以處理哪些URL 請求 2. 在控制器的 類定義 及 方法定義處 都可以標註@RequestMapping 類定義處: 提供初步的請求對映資訊。 相對於 WEB 應用的根目錄

一個線上問題分析binlog與內部XA事務提交過程

引入 實例 only 定義 api bug 功能 觸發 技術分享 1. 問題業務上新增一條訂單記錄,用戶接收到BinLake拉取的MySQL從庫數據消息後,馬上根據消息內的訂單號去查詢同一個MySQL從庫,發現有些時候無法查到該條數據,等待大約500ms~1000ms

ASP.NET/MVC/Core的HTTP請求流程

ASP.NET HTTP管道(Pipeline)模型 1. 先講一點,再深刻思考 一般我們都在寫業務程式碼,優化頁面,優化邏輯之間內徘徊。也許我們懂得HTTP,HTTPS的GET,POST,但是我們大部分人是不知道ASP是如何去解析HTTP,或者IIS是如何去處理頁面請求。我們只知道WebForm拉控制元

Spring MVC 資料繫結流程分析

1.    資料繫結流程原理★ ①   Spring MVC 主框架將 ServletRequest  物件及目標方法的入參例項傳遞給 WebDataBinderFactory 例項,以建立 DataBinder 例項物件 ②

vue + axios---封裝一個http請求

在使用vue開發時,官方推薦使用axios來請求介面 // axios官方地址 https://github.com/axios/axios 但是axios並不像 vue-resource 一樣擁有install,即不能直接 Vue.use(axios) 來使用,所以需要我們自己根據axios來寫

如何判斷一個HTTP請求是瀏覽器請求還是應用程式請求

1、獲取請求的request HttpServletRequest request=ServletActionContext.getRequest(); 2、攔截器中判斷請求頭 通常判斷來自手機端的請求還是PC端的請求只需要判斷: request.getHea

Spring MVC : Model和View名稱生成最終的View

當我們使用 Spring MVC開發Web應用頁面時,一般會使用某種檢視模版引擎技術,比如FreeMarker,Velocity之類的,然後還會寫很多控制器方法用來處理某個請求,這些控制器方法基本的套路是: 寫一個檢視模板,配置到合適的位置; 控制器方法接收處

容器完整處理一個http請求過程

初學java web的朋友們應該都知道tomcat容器,但是tomcat是如何完成一次http請求的過程,這裡做一個記錄。 當用戶在客戶端點選一個連結,該連結的URL指向一個servlet,經過網路轉發到應用所在的web伺服器的,此時web伺服器不是直接把申請發給servlet本身,而是傳送給部署該s

一個http請求的詳細過程

首先http是一個應用層的協議,在這個層的協議,只是一種通訊規範,也就是因為雙方要進行通訊,大家要事先約定一個規範。 1.連線 當我們輸入這樣一個請求時,首先要建立一個socket連線,因為socket是通過ip和埠建立的,所以之前還有一個DNS解析過程,把www.m

Spring mvc 零搭建

以eclipse 為例一:new Dynamic Web Project(如果沒有web.xml,輸入完專案名點下一步,勾選Generate web.xml deployment descriptor)二:在WebContent 寫一個靜態頁面 hello.html(試試we

SpringMVC:處理一個http請求的完整過程

SpringMVC是一個基於DispatcherServlet的MVC框架,每一個請求最先訪問的都是DispatcherServlet,DispatcherServlet負責轉發每一個Request請求給相應的Handler,Handler處理以後再返回相

Tomcat處理一個HTTP請求過程

一、Tomcat的組成 (1)Server伺服器元素代表整個catalina servlet容器。是單例模式。 (2)ServiceService是這樣一個集合:它由一個或者多個Connector組成,以及一個Engine,負責處理所有Connector所獲得的客戶請求。

一個HTTP請求例項

一個 HTTP 請求例項12當用戶點選回車按鈕,瀏覽器將頁面的請求通過網路傳送到 Web 伺服器。3Web 伺服器接收請求並解析請求資訊。在 Web 伺服器的配置檔案中有配置當前專案根目錄路徑。由於當前訪問的 URL 地址不包含子路徑,Web 伺服器會查詢配置檔案的 inde

Jmeter:Regular Expression Extractor正則表示式提取器上一個http請求報文內容作為下一個請求的引數

正則表示式提取器說明 新增元件 配置 引用 下面說明是參考網上的文章 說明:   (1)引用名稱:下一個請求要引用的引數名稱,如填寫title,則可用${title}引用它。   (2)正則表示式:     ():括起來的部分就是要提取的。