codecamp

Client-Server overview

先决条件: 基本的计算机素养。 基本了解Web服务器是什么。
目的: 要了解动态网站中的客户端 - 服务器交互,特别是需要由服务器端代码执行哪些操作。

在讨论中没有真正的代码,因为我们还没有选择使用Web框架来编写我们的代码! 然而,此讨论仍然非常相关,因为所描述的行为必须由您的服务器端代码实现,无论您选择哪种编程语言或Web框架。

Web服务器和HTTP(引文)

网络浏览器使用网络服务器,使用 H yper strong> T ext T 传输 P 协议( HTTP"> HTTP )。 当您点击网页上的链接,提交表单或运行搜索时,浏览器会向服务器发送 HTTP请求

此请求包括:

  • A URL identifying the target server and resource (e.g. an HTML file, a particular data point on the server, or a tool to run).
  • A method that defines the required action (for example, to get a file or to save or update some data). The different methods/verbs and their associated actions are listed below:
    • GET: Get a specific resource (e.g. an HTML file containing information about a product, or a list of products). 
    • POST: Create a new resource (e.g. add a new article to a wiki, add a new contact to a database). 
    • HEAD: Get the metadata information about a specific resource without getting the body like GET would. You might for example use a HEAD request to find out the last time a resource was updated, and then only use the (more "expensive") GET request to download the resource if it has changed. 
    • PUT: Update an existing resource (or create a new one if it doesn't exist).
    • DELETE: Delete the specified resource.
    • TRACE, OPTIONS, CONNECT, PATCH: These verbs are for less common/advanced tasks, so we won't cover them here.
  • Additional information can be encoded with the request (for example, HTML form data). Information can be encoded as:
    • URL parameters: GET requests encode data in the URL sent to the server by adding name/value pairs onto the end of it — for example http://mysite.com?name=Fred&age=11. You always have a question mark (?) separating the rest of the URL from the URL parameters, an equals sign (=) separating each name from its associated value, and an ampersand (&) separating each pair.  URL parameters are inherently "insecure" as they can be changed by users and then resubmitted. As a result URL parameters/GET requests are not used for requests that update data on the server.
    • POST data. POST requests add new resources, the data for which is encoded within the request body.
    • Client-side cookies. Cookies contain session data about the client, including keys that the server can use to determine their logged in status and permissions/accesses to resources.

Web服务器等待客户端请求消息,在到达时处理它们,并使用HTTP响应消息回复Web浏览器。 响应包含指示请求是否成功的 HTTP响应状态代码(例如" 200 OK "如果找不到资源," 403 ForBidden "如果用户未授权 查看资源等)。 GET 请求的成功响应的正文将包含所请求的资源。

当HTML页面返回时,它由Web浏览器呈现。 作为处理的一部分,浏览器可以发现到其他资源的链接(例如,通常引用JavaScript和CSS页面的HTML页面),并且将发送单独的HTTP请求以下载这些文件。

静态和动态网站(在以下部分讨论)使用完全相同的通信协议/模式。

GET请求/响应示例

您可以通过点击链接或在网站(如搜索引擎首页)上进行搜索来创建一个简单的 GET 请求。 例如,当您在MDN上执行"客户端服务器概述"术语搜索时发送的HTTP请求将看起来很像下面显示的文本(它将不完全相同,因为消息的部分取决于您的浏览器/设置 )。

HTTP消息的格式在"网络标准"( RFC7230 )中定义。 你不需要知道这个级别的细节,但至少现在你知道这一切都来自哪里!

The request

请求的每一行包含有关它的信息。 第一部分称为标头,其中包含有关请求的有用信息,其方式与 HTML头包含的有用信息相同 有关HTML文档的信息(但不是实际内容本身,它在正文中):

GET https://developer.mozilla.org/en-US/search?q=client+server+overview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev HTTP/1.1
Host: developer.mozilla.org
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: https://developer.mozilla.org/en-US/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8,es;q=0.6
Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _gat=1; _ga=GA1.2.1688886003.1471911953; ffo=true

第一行和第二行包含我们上面讨论的大多数信息:

  • The type of request (GET).
  • The target resource URL (/en-US/search).
  • The URL parameters (q=client%2Bserver%2Boverview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev).
  • The target/host website (developer.mozilla.org).
  • The end of the first line also includes a short string identifying the specific protocol version (HTTP/1.1).

最后一行包含关于客户端cookie的信息 - 您可以看到,在这种情况下,cookie包括用于管理会话的ID( Cookie:sessionid = 6ynxs23n521lu21b1t136rhbv7ezngie; ... )。

其余行包含有关所使用的浏览器的信息以及它可以处理的响应类型。 例如,你可以看到:

  • My browser (User-Agent) is Mozilla Firefox (Mozilla/5.0).
  • It can accept gzip compressed information (Accept-Encoding: gzip).
  • It can accept the specified set of characters (Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7) and languages (Accept-Language: de,en;q=0.7,en-us;q=0.3).
  • The Referer line indicates the address of the web page that contained the link to this resource (i.e. the origin of the request, https://developer.mozilla.org/en-US/).

HTTP请求也可以有一个主体,但在这种情况下它是空的。

The response

此请求的响应的第一部分如下所示。 标题包含如下信息:

  • The first line includes the response code 200 OK, which tells us that the request succeeded.
  • We can see that the response is text/html formatted (Content-Type).
  • We can also see that it uses the UTF-8 character set (Content-Type: text/html; charset=utf-8).
  • The head also tells us how big it is (Content-Length: 41823).

在消息结束时,我们会看到正文内容 - 其中包含请求返回的实际HTML。

HTTP/1.1 200 OK
Server: Apache
X-Backend-Server: developer1.webapp.scl3.mozilla.com
Vary: Accept,Cookie, Accept-Encoding
Content-Type: text/html; charset=utf-8
Date: Wed, 07 Sep 2016 00:11:31 GMT
Keep-Alive: timeout=5, max=999
Connection: Keep-Alive
X-Frame-Options: DENY
Allow: GET
X-Cache-Info: caching
Content-Length: 41823



<!DOCTYPE html>
<html lang="en-US" dir="ltr" class="redesign no-js"  data-ffo-opensanslight=false data-ffo-opensans=false >
<head prefix="og: http://ogp.me/ns#">
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <script>(function(d) { d.className = d.className.replace(/\bno-js/, ''); })(document.documentElement);</script>
  ...

请求的其余部分包括关于响应的信息(例如,当它被生成时),服务器,以及它如何期望浏览器处理页面(例如 X-Frame-Options:DENY 浏览器不允许此网页嵌入 < iframe> )。

POST请求/响应示例

当您提交包含要保存在服务器上的信息的表单时,会生成HTTP POST

The request

下面的文本显示了当用户在此网站上提交新的配置文件详细信息时发出的HTTP请求。 请求的格式与之前显示的 GET 请求示例几乎相同,但第一行将此请求标识为 POST

POST https://developer.mozilla.org/en-US/profiles/hamishwillee/edit HTTP/1.1
Host: developer.mozilla.org
Connection: keep-alive
Content-Length: 432
Pragma: no-cache
Cache-Control: no-cache
Origin: https://developer.mozilla.org
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: https://developer.mozilla.org/en-US/profiles/hamishwillee/edit
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8,es;q=0.6
Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; _gat=1; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _ga=GA1.2.1688886003.1471911953; ffo=true

csrfmiddlewaretoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT&user-username=hamishwillee&user-fullname=Hamish+Willee&user-title=&user-organization=&user-location=Australia&user-locale=en-US&user-timezone=Australia%2FMelbourne&user-irc_nickname=&user-interests=&user-expertise=&user-twitter_url=&user-stackoverflow_url=&user-linkedin_url=&user-mozillians_url=&user-facebook_url=

主要的区别是URL没有任何参数。 您可以看到,表单中的信息在请求的正文中进行了编码(例如,新用户的全名通过以下方式设置:& user-fullname = Hamish + Willee )。

The response

请求的响应如下所示。 状态代码" 302 Found "告诉浏览器该帖子成功,并且它必须发出第二个HTTP请求来加载在 Location 字段中指定的页面。 该信息类似于对 GET 请求的响应。

HTTP/1.1 302 FOUND
Server: Apache
X-Backend-Server: developer3.webapp.scl3.mozilla.com
Vary: Cookie
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
Date: Wed, 07 Sep 2016 00:38:13 GMT
Location: https://developer.mozilla.org/en-US/profiles/hamishwillee
Keep-Alive: timeout=5, max=1000
Connection: Keep-Alive
X-Frame-Options: DENY
X-Cache-Info: not cacheable; request wasn't a GET or HEAD
Content-Length: 0

注意:这些示例中显示的HTTP响应和请求是使用 Fiddler a>应用程序,但您可以使用网络嗅探器获取类似的信息(例如 http://web-sniffer.net/ >)或使用浏览器扩展程序,如 HttpFox 。 你可以自己尝试一下。 使用任何链接的工具,然后浏览网站并编辑个人资料信息以查看不同的请求和响应。 大多数新式浏览器还有监控网络请求的工具(例如,Firefox中的网络监控工具) )。

静态网站

每当请求特定资源时,静态网站是从服务器返回相同的硬编码内容的网站。 例如,如果您在 /static/myproduct1.html 上有一个关于产品的页面,则该同一页面将返回给每个用户。 如果您向网站添加其他类似产品,则需要添加其他网页(例如, myproduct2.html )等。 这可能开始真的效率低下 - 当你得到成千上万的产品页面会发生什么? 您会在每个网页(基本网页模板,结构等)上重复大量代码,如果您想更改网页结构的任何内容,例如添加新的"相关产品"部分, 必须单独更改每个页面。

注意:如果您的网页数量较少,并且希望向每个用户发送相同的内容,则静态网站非常棒。 然而,随着页面数量变大,它们可以具有显着的维护成本。

让我们回顾一下这是如何工作的,再看一下我们在上一篇文章中看到的静态网站架构图。

当用户想要导航到页面时,浏览器发送HTTP GET 请求,指定其HTML页面的URL。 服务器从其文件系统检索所请求的文档,并返回包含该文档和 HTTP响应的HTTP响应 状态码"(表示成功)的" 200 OK "。 如果文件不存在于服务器上,服务器可能会返回不同的状态代码,例如" 404 Not Found ",如果文件存在,则会返回" 301 Moved Permanently 但已重定向到其他位置。

静态站点的服务器将只需要处理GET请求,因为服务器不存储任何可修改的数据。 它也不会根据HTTP请求数据(例如网址参数或Cookie)更改其响应。

然而,当学习服务器端编程时,了解静态站点的工作原理仍然有用,因为动态站点以完全相同的方式处理对静态文件(CSS,JavaScript,静态图像等)的请求。

动态网站

动态网站是一种可根据特定请求网址和数据生成和返回内容的网站(而不是始终为特定网址返回相同的硬编码文件)。 使用产品站点的示例,服务器将产品"数据"存储在数据库中而不是单个HTML文件。 当接收到对产品的HTTP GET 请求时,服务器确定产品ID,从数据库获取数据,然后通过将数据插入到HTML模板中来构造响应的HTML页面。 这相对于静态网站有以下优点:

使用数据库允许以容易扩展,可修改和可搜索的方式有效地存储产品信息。

使用HTML模板可以很容易地更改HTML结构,因为这只需要在一个地方,在单个模板中完成,而不是跨越可能数千个静态页面。

动态请求的剖析

本部分提供了"动态"HTTP请求和响应周期的逐步概述,基于我们在上一篇文章中详细介绍的内容。 为了"保持事物真实",我们将使用运动团队经理网站的上下文,教练可以在HTML表单中选择他们的球队名称和团队规模,并获得他们下一场比赛的建议"最佳阵容"。

下图显示了"团队教练"网站的主要元素,以及教练访问其"最佳团队"列表时的操作顺序的编号标签。 网站的动态部分是 Web应用程序(这是我们将如何参考处理HTTP请求和返回HTTP响应的服务器端代码),数据库 em>,其中包含有关玩家,团队,教练及其关系以及 HTML模板的信息。

在教练提交队伍名称和球员数量的表格后,操作的顺序是:

  1. The web browser creates an HTTP GET request to the server using the base URL for the resource (/best) and encoding the team and player number either as URL parameters (e.g. /best?team=my_team_name&show=11) or as part of the URL pattern (e.g. /best/my_team_name/11/). A GET request is used because the request is only fetching data (not modifying data).
  2. The Web Server detects that the request is "dynamic" and forwards it to the Web Application for processing (the web server determines how to handle different URLs based on pattern matching rules defined in its configuration).
  3. The Web Application identifies that the intention of the request is to get the "best team list" based on the URL (/best/) and finds out the required team name and number of players from the URL. The Web Application then gets the required information from the database (using additional "internal" parameters to define which players are "best", and possibly also getting the identity of the logged in coach from a client-side cookie).
  4. The web application dynamically creates an HTML page by putting the data (from the database) into placeholders inside an HTML template.
  5. The Web Application returns the generated HTML to the web browser (via the Web Server), along with an HTTP status code of 200 ("success"). If anything prevents the HTML being returned then the Web Application will return another code — for example "404" to indicate that the team does not exist.
  6. The Web Browser will then start to process the returned HTML, sending separate requests to get any other CSS or JavaScript files that it references (see step 7).
  7. The Web Server loads static files from the file system and returns them to the browser directly (again, correct file handling is based on configuration rules and URL pattern matching).

更新数据库中的记录的操作将类似地处理,除了像任何数据库更新一样,来自浏览器的HTTP请求应被编码为 POST 请求。

做其他工作

的作业是接收HTTP请求并返回HTTP响应。 虽然与数据库交互以获取或更新信息是非常常见的任务,但代码可以同时做其他事情,或根本不与数据库交互。

Web应用程序可能执行的额外任务的一个好例子是向用户发送电子邮件,以确认他们在网站上的注册。 该站点还可能执行日志记录或其他操作。

返回HTML以外的内容

服务器端网站代码不必在响应中返回HTML片段/文件。 它可以改为动态创建和返回其他类型的文件(文本,PDF,CSV等)甚至数据(JSON,XML等)。

将数据返回到Web浏览器以便它可以动态更新自己的内容的想法( AJAX )已经存在了一段时间。 最近的"单页应用程序"已经变得流行,整个网站都用一个HTML文件编写,并在需要时动态更新。 使用这种应用程序创建的网站将大量的计算成本从服务器推送到Web浏览器,并且可能导致网站看起来更像本地应用程序(响应速度快等)。

Web框架简化了服务器端Web编程

服务器端Web框架使编写代码来处理上面描述的操作更容易。

它们执行的最重要的操作之一是提供简单的机制来将不同资源/页面的URL映射到特定的处理程序函数。 这使得更容易保持与每种类型的资源相关联的代码分离。 它还具有维护方面的优点,因为您可以更改用于在一个位置提供特定功能的URL,而无需更改处理函数。

例如,考虑下面的将两个URL模式映射到两个视图函数的Django(Python)代码。 第一种模式确保具有资源URL / best 的HTTP请求将被传递到 views 模块中的 index() 。 具有模式" / best / junior "的请求将被传递到 junior()视图函数。

# file: best/urls.py
#

from django.conf.urls import url

from . import views

urlpatterns = [
    # example: /best/
    url(r'^$', views.index),
    # example: /best/junior/
    url(r'^junior/$', views.junior),
]

注意: url()函数中的第一个参数可能看起来有点奇怪(例如 r\'^ junior / $\'), 称为"正则表达式"(RegEx或RE)的模式匹配技术。 你不需要知道正则表达式在这一点上的工作方式,除了它们允许我们匹配URL中的模式(而不是上面的硬编码值),并将它们用作我们的视图函数中的参数。 例如,一个真正简单的RegEx可能会说"匹配一个单一的大写字母,后跟4到7个小写字母"。

Web框架还使得视图函数从数据库获取信息变得容易。 我们的数据结构在模型中定义,这些模型是定义要存储在底层数据库中的字段的Python类。 如果我们有一个名为 Team 的模型,其字段为" team_type ",那么我们可以使用一个简单的查询语法来取回所有具有特定类型的团队。

下面的示例获取了所有具有(区分大小写) team_type "junior"的所有小组的列表 - 请注意格式:字段名称( team_type )后跟双下划线 ,然后是要使用的匹配类型(在本例中为 exact )。 还有许多其他类型的火柴,我们可以菊花链。 我们还可以控制返回的结果的顺序和数量。

#best/views.py

from django.shortcuts import render

from .models import Team 


def junior(request):
    list_teams = Team.objects.filter(team_type__exact="junior")
    context = {'list': list_teams}
    return render(request, 'best/index.html', context)

junior()函数获取初级团队列表之后,它调用 render()函数,传递原始的 HttpRequest ,以及定义要包括在模板中的信息的"上下文"对象。 render()函数是一个方便的函数,它使用上下文和HTML模板生成HTML,并在 HttpResponse 对象中返回它。

显然,Web框架可以帮助您完成许多其他任务。 我们在下一篇文章中讨论了更多的好处和一些流行的Web框架选择。

概要

在这一点上,您应该对服务器端代码必须执行的操作有一个很好的概述,并且了解服务器端Web框架可以使这更容易的一些方法。

在下面的模块中,我们将帮助您为您的第一个网站选择最好的Web框架。

Website security
Handling common JavaScript problems
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录
CSS

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }