Speaking before:
Request and response are two important links in the life cycle of the framework, and they are the two ends of the framework. The request is responsible for taking over the client's request information, and provides a large number of external interfaces to obtain more refined data. The response is responsible for outputting the results of business logic execution in various forms. This chapter will introduce the implementation details of requests and responses in detail from nine aspects. The nine subsections are: request information, request variables, request type, header information, request cache, response type, response output, response parameters, and redirection. Next are the details:
2.1 Request Information:
What is request information? Request information refers to all the information sent by the client requesting the server, including the request protocol, domain name, port, request method, request parameters, etc. For this information, the PHP language stores them in some super-global arrays, so-called The request object to take over the request information is to take over these super global arrays, please see the specific code:
1. // This is the initialization method of the Request class, taking over the superglobal data except $_SESSION 2. // vendortopthinkframeworksrcthinkRequest.php 3. public static function __make(App $app) 4. { 5. $request = new static(); 7. if (function_exists('apache_request_headers') && $result = apache_request_headers()) { 8. $header = $result; 9. } else { 10. $header = []; 11. $server = $_SERVER; 12. foreach ($server as $key => $val) { 13. if (0 === strpos($key, 'HTTP_')) { 14. $key = str_replace('_', '-', strtolower(substr($key, 5))); 15. $header[$key] = $val; 16. } 17. } 18. if (isset($server['CONTENT_TYPE'])) { 19. $header['content-type'] = $server['CONTENT_TYPE']; 20. } 21. if (isset($server['CONTENT_LENGTH'])) { 22. $header['content-length'] = $server['CONTENT_LENGTH']; 23. } 24. } 26. $request->header = array_change_key_case($header); 27. $request->server = $_SERVER; 28. $request->env = $app->env; 30. $inputData = $request->getInputData($request->input); 32. $request->get = $_GET; 33. $request->post = $_POST ?: $inputData; 34. $request->put = $inputData; 35. $request->request = $_REQUEST; 36. $request->cookie = $_COOKIE; 37. $request->file = $_FILES ?? []; 39. return $request; 40. }
After taking over this series of information, the Request class obtains and outputs all of the information through various refined interfaces, and provides those interfaces to the outside world. You can refer to the manual, and here is an analysis of several important interfaces.
Current access domain name or IP: host() method
1. // Get access domain name vendortopthinkframeworksrcthinkRequest.php Line 1754 2. public function host(bool $strict = false): string 3. { 4. if ($this->host) { 5. $host = $this->host; 6. } else { 8. // Obtained through the HTTP_X_FORWARDED_HOST attribute or HTTP_HOST in $_SERVER 9. $host = strval($this->server('HTTP_X_FORWARDED_HOST') ?: $this->server('HTTP_HOST')); 10. } 11. // Here is to judge whether to include the port or not 12. return true === $strict && strpos($host, ':') ? strstr($host, ':', true) : $host; 13. }
Current full URL: url() method
1. // Get current full URL including QUERY_STRING 2. // vendortopthinkframeworksrcthinkRequest.php line 460 3. public function url(bool $complete = false): string 4. { 5. if ($this->url) { 6. $url = $this->url; 7. } elseif ($this->server('HTTP_X_REWRITE_URL')) { 8. $url = $this->server('HTTP_X_REWRITE_URL'); 9. } elseif ($this->server('REQUEST_URI')) { 10. $url = $this->server('REQUEST_URI'); 11. } elseif ($this->server('ORIG_PATH_INFO')) { // This property will appear when the web server redirects 12. $url = $this->server('ORIG_PATH_INFO') . (!empty($this->server('QUERY_STRING')) ? '?' . $this->server('QUERY_STRING') : ''); 13. } elseif (isset($_SERVER['argv'][1])) { 14. $url = $_SERVER['argv'][1]; 15. } else { 16. $url = ''; 17. } 19. return $complete ? $this->domain() . $url : $url; 20. }
2.2 Input variables:
Input variable refers to the input information that can be changed, so what is the input information that can be changed? For example, query parameters, upload files, and Post request bodies can be changed. Users can obtain or save information from the server through these changeable things. For example, they can obtain different product information through changes in query parameters, and submit pictures through Information to save your own photos, these are input variables for the framework, the Request (request) class provides a rich API to help us get this information, please see the detailed code:
Get the $_POST variable: post() method
1. // Get POST parameters, pass the attribute name to get its corresponding value 2. // vendortopthinkframeworksrcthinkRequest.php line 961 3. public function post($name = '', $default = null, $filter = '') 4. { 5. if (is_array($name)) { 6. return $this->only($name, $this->post, $filter); 7. } 9. return $this->input($this->post, $name, $default, $filter); 10. } 13. // Get variables and support filtering, whether get() post() or param() depends on this method 14. // vendortopthinkframeworksrcthinkRequest.php line 1241 15. public function input(array $data = [], $name = '', $default = null, $filter = '') 16. { 17. if (false === $name) { 18. // get raw data 19. return $data; 20. } 22. $name = (string) $name; 23. if ('' != $name) { 24. // resolve name 25. if (strpos($name, '/')) { 26. [$name, $type] = explode('/', $name); 27. } 29. $data = $this->getData($data, $name); 31. if (is_null($data)) { 32. return $default; 33. } 35. if (is_object($data)) { 36. return $data; 37. } 38. } 40. $data = $this->filterData($data, $filter, $name, $default); 42. if (isset($type) && $data !== $default) { 43. // coercion 44. $this->typeCast($data, $type); 45. } 47. return $data; 48. }
Get the $_FILES variable (upload file information): file() method
1. // Get the information of the uploaded file, here is an array of objects, each uploaded file will generate an upload object 2. // vendortopthinkframeworksrcthinkRequest.php line 1128 3. public function file(string $name = '') 4. { 5. $files = $this->file; // 6. if (!empty($files)) { 8. if (strpos($name, '.')) { 9. [$name, $sub] = explode('.', $name); 10. } 12. // Process upload files 13. $array = $this->dealUploadFile($files, $name); 15. if ('' === $name) { 16. // get all files 17. return $array; 18. } elseif (isset($sub) && isset($array[$name][$sub])) { 19. return $array[$name][$sub]; 20. } elseif (isset($array[$name])) { 21. return $array[$name]; 22. } 23. } 24. } 26. // Upload file object to create vendortopthinkframeworksrcthinkRequest.php line 1175 27. $item[] = new UploadedFile($temp['tmp_name'], $temp['name'], $temp['type'], $temp['error']); 29. // File upload depends on the flysystem component, which we will introduce later
2.3 Request Type:
The request type refers to the HTTP request type. There are five HTTP request types in total: GET, POST, PUT, DELETE, and HEAD. The interface provided by the Request class is divided into two categories. One is to obtain the current request type, and the other is to determine whether it is a certain type. Next, we will analyze two representative API s:
Get the current request type: method() method
1. // Get request type Get request type supports type forgery, if the request type is forged, get the forged type first 2. // vendortopthinkframeworksrcthinkRequest.php line 717 3. public function method(bool $origin = false): string 4. { 5. if ($origin) { 6. // Get the original request type 7. return $this->server('REQUEST_METHOD') ?: 'GET'; 8. } elseif (!$this->method) { 9. if (isset($this->post[$this->varMethod])) { 10. $method = strtolower($this->post[$this->varMethod]); 11. if (in_array($method, ['get', 'post', 'put', 'patch', 'delete'])) { 12. $this->method = strtoupper($method); 13. $this->{$method} = $this->post; 14. } else { 15. $this->method = 'POST'; 16. } 17. unset($this->post[$this->varMethod]); 18. } elseif ($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')) { 19. $this->method = strtoupper($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')); 20. } else { 21. $this->method = $this->server('REQUEST_METHOD') ?: 'GET'; 22. } 23. } 25. return $this->method; 26. }
Determine whether AJAX request: isAjax() method
1. // Judging whether it is an ajax request is mainly judged by the HTTP_X_REQUESTED_WITH attribute, which is only available for ajax requests 2. // ajax requests also support type forgery and have limited access to forged types. 3. // vendortopthinkframeworksrcthinkRequest.php line 1545 4. public function isAjax(bool $ajax = false): bool 5. { 6. $value = $this->server('HTTP_X_REQUESTED_WITH'); 7. $result = $value && 'xmlhttprequest' == strtolower($value) ? true : false; 9. if (true === $ajax) { 10. return $result; 11. } 13. return $this->param($this->varAjax) ? true : $result; 14. }
2.4 Request header information:
The request header information refers to the HTTP request message header, which organizes information in the form of "attribute name: attribute value", and the server obtains most of the client information accordingly. Request obtains this information in two ways, the first is from the $_SERVER superglobal array, and the second is obtained from the apache_request_headers method (provided that Apache is used as the web container), see the code:
1. // Get vendortopthinkframeworksrcthinkRequest.php line 307 in the initialization method 2. public static function __make(App $app) 3. { 4. $request = new static(); 6. // This method is only available under the Apache container 7. if (function_exists('apache_request_headers') && $result = apache_request_headers()) { 8. $header = $result; 9. } else { 10. // Extract from $_SERVER if not 11. $header = []; 12. $server = $_SERVER; 13. foreach ($server as $key => $val) { 14. if (0 === strpos($key, 'HTTP_')) { 15. $key = str_replace('_', '-', strtolower(substr($key, 5))); 16. $header[$key] = $val; 17. } 18. } 19. if (isset($server['CONTENT_TYPE'])) { 20. $header['content-type'] = $server['CONTENT_TYPE']; 21. } 22. if (isset($server['CONTENT_LENGTH'])) { 23. $header['content-length'] = $server['CONTENT_LENGTH']; 24. } 25. } 26. }
Request information can be obtained through the header method:
1. // Set or get the request header vendortopthinkframeworksrcthinkRequest.php Line 1221 2. public function header(string $name = '', string $default = null) 3. { 4. if ('' === $name) { 5. return $this->header; 6. } 8. $name = str_replace('_', '-', strtolower($name)); 10. return $this->header[$name] ?? $default; 11. }
2.5 Request cache:
What is request caching? It is to cache the requested content on the client side. The server side of the next request only needs to respond with the status code, and the browser automatically reads the content from the cache, which can greatly improve the user experience. How is such a good function achieved? In fact, it is implemented through global middleware, so how to open it? Look at the code:
1. <?php 2. // Step 1: Uncomment the global cache middleware 3. // Global middleware definition file appmiddleware.php 4. return [ 5. // global request cache 6. thinkmiddlewareCheckRequestCache::class, 7. // Multilingual loading 8. thinkmiddlewareLoadLangPack::class, 9. // Session initialization 10. thinkmiddlewareSessionInit::class 11. ]; 13. // Step 2: Set this item in the routing configuration to true 14. // configroute.php line 30 16. // Whether to enable request caching true automatic caching Support setting request caching rules 17. 'request_cache_key' => true,
Next, the implementation principle is revealed, and the code is as follows:
1. // Middleware entry function and only support get request 2. public function handle($request, Closure $next, $cache = null) 3. { 4. if ($request->isGet() && false !== $cache) { 5. $cache = $cache ?: $this->getRequestCache($request); 7. if ($cache) { 8. if (is_array($cache)) { 9. [$key, $expire, $tag] = $cache; 10. } else { 11. $key = str_replace('|', '/', $request->url()); 12. $expire = $cache; 13. $tag = null; 14. } 16. if (strtotime($request->server('HTTP_IF_MODIFIED_SINCE', '')) + $expire > $request->server('REQUEST_TIME')) { 17. // read cache 18. return Response::create()->code(304); 19. } elseif (($hit = $this->cache->get($key)) !== null) { 20. [$content, $header, $when] = $hit; 21. if (null === $expire || $when + $expire > $request->server('REQUEST_TIME')) { 22. return Response::create($content)->header($header); 23. } 24. } 25. } 26. } 28. $response = $next($request); 30. if (isset($key) && 200 == $response->getCode() && $response->isAllowCache()) { 31. $header = $response->getHeader(); 32. $header['Cache-Control'] = 'max-age=' . $expire . ',must-revalidate'; 33. $header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT'; 34. $header['Expires'] = gmdate('D, d M Y H:i:s', time() + $expire) . ' GMT'; 36. $this->cache->tag($tag)->set($key, [$response->getContent(), $header, time()], $expire); 37. } 39. return $response; 40. }
2.6 Response Type:
The response type is the form in which the server responds to the content of the client. The framework implements seven response types: File, Html, Json, Jsonp, Redirect, View, and Xml. In fact, there are seven response classes, all of which inherit the Response class, and override some methods of the parent class. The following figure shows the positions defined by the seven classes:
Next, let's introduce the meanings of the seven response classes:
File: Download the file by modifying the response header information.
Html: It is the response html page, which is the vast majority of response forms.
Json: Response json data for API response.
Jsonp: This is a cross-domain request-response.
Redirect : This is a redirect.
View: This is the nature of the response view or the html page. The advantage of this is that the template can be rendered without calling the fetch method in the view.
Xml: This is the response xml data.
2.7 Response output:
The response output has actually been introduced in the life cycle, and here are a few more points. The response output is to call the send method of Response. An important operation in this method is to obtain the output data. See the code:
1. public function send(): void 2. { 3. // Process output data 4. $data = $this->getContent(); 6. // omit some code 7. } 9. public function getContent(): string 10. { 11. if (null == $this->content) { 12. $content = $this->output($this->data); 14. if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([ 15. $content, 16. '__toString', 17. ]) 18. ) { 19. throw new InvalidArgumentException(sprintf('variable type error: %s', gettype($content))); 20. } 22. $this->content = (string) $content; 23. } 25. return $this->content; 26. }
The output method is overridden in six classes except Html. This method determines the difference in output content. Let's take a look at the output method of the File class. code show as below:
1. // This code implements a file download function vendortopthinkframeworksrcthinkresponseFile.php 2. protected function output($data) 3. { 4. if (!$this->isContent && !is_file($data)) { 5. throw new Exception('file not exists:' . $data); 6. } 8. ob_end_clean(); 10. if (!empty($this->name)) { 11. $name = $this->name; 12. } else { 13. $name = !$this->isContent ? pathinfo($data, PATHINFO_BASENAME) : ''; 14. } 16. if ($this->isContent) { 17. $mimeType = $this->mimeType; 18. $size = strlen($data); 19. } else { 20. $mimeType = $this->getMimeType($data); 21. $size = filesize($data); 22. } 24. $this->header['Pragma'] = 'public'; 25. $this->header['Content-Type'] = $mimeType ?: 'application/octet-stream'; 26. $this->header['Cache-control'] = 'max-age=' . $this->expire; 27. $this->header['Content-Disposition'] = ($this->force ? 'attachment; ' : '') . 'filename="' . $name . '"'; 28. $this->header['Content-Length'] = $size; 29. $this->header['Content-Transfer-Encoding'] = 'binary'; 30. $this->header['Expires'] = gmdate("D, d M Y H:i:s", time() + $this->expire) . ' GMT'; 32. $this->lastModified(gmdate('D, d M Y H:i:s', time()) . ' GMT'); 34. return $this->isContent ? $data : file_get_contents($data); 35. }
2.8 Response parameters:
The so-called response parameters refer to the response content, status code, and response headers. Although this information can be set uniformly, Response also provides a separate method to set these contents, see the code demonstration:
response content
1. // Output data settings 2. public function data($data) 3. { 4. $this->data = $data; 6. return $this; 7. }
status code
1. // Set HTTP status code 2. public function code(int $code) 3. { 4. $this->code = $code; 6. return $this; 7. }
response header
1. // set response headers 2. public function header(array $header = []) 3. { 4. $this->header = array_merge($this->header, $header); 6. return $this; 7. }
2.9 Redirect:
Redirection is a type of response, so I won't introduce it here, just look at the implementation code of the framework:
1. // The implementation is achieved through location where $data is url 2. protected function output($data): string 3. { 4. $this->header['Location'] = $data; 6. return ''; 7. }
Dear readers, this is the end of the introduction to request and response. Thank you for reading. If you are still interested in the text tutorial, you can move to the downlink address to watch the video tutorial, and you can communicate one-on-one.
Tutorial address: https://edu.csdn.net/course/detail/28045