客户端服务端交互概述

客户端服务端交互概述

网络服务器和 HTTP(入门)

网络浏览器经过超文本符号言语传输协议(HTTP)与网络服务器(web servers)。当你在网页上点击一个链接、提交一个表单、或许进行一次查找的时分,浏览器发送一个 HTTP 恳求给服务器。

这个恳求包括:

  • 一个用来辨认方针服务器和资源(比方一个 HTML 文档、存储在服务器上的一个特定的数据、或许一个用来运行的东西等)的 URL。
  • 一个界说了恳求行为的方法(比方,取得一个文档或许上传某些数据)。不同的方法/动作以及与他们相关的行为罗列如下:
    • GET:获取一份指定(比方一个包括了一个产品或许一系列产品相关信息的 HTML 文档)。
    • POST:创立一份新的资源(比方给 wiki 添加一片新的文章、给数据库添加一个新的节点)。
    • HEAD: 获取有关指定资源的元数据信息,而不会得到像 GET 的内容部分。例如,您能够运用 HEAD 恳求来查找前次更新资源的时间,然后仅运用(更“昂贵”)GET 恳求下载资源(假如已更改)。
    • PUT:更新一份现已存在的资源(或许在该资源不存在的情况下创立一份新的)。
    • DELETE:删去指定的资源。
    • TRACEOPTIONSCONNECT、PATCH:这些动作是为一些不常见使命规划的,因而咱们在这儿的讲解不会涉及到它们。
  • 额定的信息能够和恳求一同被编码(比方 HTML 表单数据)。信息能够被编码成如下:
    • URL 参数:GET 恳求经过在 URL 结尾添加的键值对,来编码包括在发送给服务器的 URL 中的数据——比方,http://mysite.com?name=Fred&age=11,你常常会用到问号(?)来将 URL 剩下的部分和 URL 参数分隔开来,一个赋值符号(=)将称号和与之相关的值分隔开来,然后一个“&”符号分割不同的键值对。当他们被用户改动然后提交时,URL 参数具有与生俱来地“不安全性”。因而,一个 URL 参数或许 GET 恳求是不会用来在服务器上更新数据的。
    • POST 数据:POST 恳求会添加新的资源,这些数据将会在恳求体中编码。
    • 客户端 cookie:cookies 包括与客户相关的会话数据,服务器能够用这些数据来判别用户的登录状况以及用户是否有拜访资源的权限。

网络服务器等候来自客户的恳求信息,当恳求到达时处理它们,然后发给浏览器 HTTP 呼应音讯。回应包括一个 HTTP 呼应状况码(HTTP Response status code)来暗示恳求是否成功 (比方 “200 OK” 连接成功, “404 Not Found” 资源没有找到,”403 Forbidden” 用户没有被授权检查资源,等等). 一个成功的呼应主体,会包括 GET 恳求所恳求的资源。

当一个 HTML 页面被返时,页面会被网络浏览器呈现出来。作为处理作业的一部分,浏览器会发现指向其他资源的链接(比方,一个 HTML 页面通常会参阅 Javascript 和 CSS 页面),而且会发送独立的 HTTP 恳求来下载这些文件。

静态网站和动态网站(在接下来的部分评论到的)正是运用同一种通信协议/模式

GET 恳求/呼应举例

你能够经过点击一个链接或许在网站进行一次查找(比方查找引擎的首页)做出一次简略的 GET 恳求。比方,当你在 MDN 上进行一次对“客户端概览”词条的查找时,HTTP 恳求就被发送出去了,你将会看到正如下面相同被展现出来的文本信息(展现出来的信息不一定是相同的,由于其中一部分信息还取决于你的浏览器)。

补白: HTTP 音讯的格局是在“网络规范”(RFC7230)中界说的。你不需求知道这个规范的细节,可是现在你至少得知道一切这些是来自哪儿的!

恳求

每一行恳求都包括着相关信息。榜首部分被称为header,而且包括着关于这个恳求的有用信息,相同地一个HTML head包括着关于 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-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7
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

榜首行和第二行包括了咱们在上面评论过的大部分信息

  • 恳求类型(GET)。
  • 方针资源的 URL(/en-US/search)。
  • URL 参数(q=client%2Bserver%2Boverview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev)。
  • 方针网站(developer.mozilla.org)。
  • 榜首行的结尾也包括了一个简短的包括了标识协议版别的字符串(HTTP/1.1)。

最后一行包括一些关于客户端 cookies 的信息——你能够看到在这种情况下 cookies 包括一个为处理远程会话准备的 ID(Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; ...)。

剩下几行包括着所运用的浏览器以及浏览器所能处理的回应类型等信息。比方,你能够在下面看到这些相关信息:

  • 我的浏览器上 (User-Agent) 是火狐 (Mozilla/5.0).
  • 它能够接纳 gzip 压缩信息 (Accept-Encoding: gzip).
  • 它能够接纳的详细编码类型 (Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7) 和言语 (Accept-Language: de,en;q=0.7,en-us;q=0.3).
  • The Referer line 提示包括资源链接的网络地址 (或许说恳求的来源是 https://developer.mozilla.org/en-US/).

恳求也能够有一个恳求体,不过在这个比方中恳求的恳求体是空的。

回应

针对这个恳求的回应的榜首部分内容展现如下。The header 包括了如下信息:

  • 榜首行包括了回应状况码 200 OK,这告知咱们恳求是成功的。
  • 咱们能够看到回应是文本 html 格局的(Content-Type)。
  • 咱们也能够看到它运用的是 UTF-8 字符集 (Content-Type: text/html; charset=utf-8).
  • The head 也告知咱们它有多大 (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>
  ...

header 的剩下部分还包括一些回应的其他信息(比方回应在什么时分生成的),有关服务器的信息,还有它希望浏览器怎么处理这个包(比方, X-Frame-Options: DENY 告知浏览器不答应这个网页嵌入在其他网站的 HTML 元素“上。

POST 恳求/呼应举例

当你提交一个表单,而且希望表单所包括的信息存储到服务器的时分,你就生成了一次 HTTP POST 恳求。

恳求

下面的文本展现了当用户在网站上提交新的文件的时分,生成的一个 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)

呼应

恳求的呼应如下。状况码”302 FOUND”告知浏览器,服务端已收到它提交的 post 恳求,它有必要再宣布第二个 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 软件来捕获的,你也能够得到类似的信息经过运用网络嗅探器(比方web-sniffer.net/)或许运用浏览器扩展例… HttpFox。你能够自己尝试一下。运用任何一个上面链接的东西,浏览一个站点并修正主要信息来调查不同的恳求和呼应。更多的现代浏览器拥有网络监控东西(例如,在 Firefox 上的 Network Monitor 东西)。

静态网站

静态网站是指每当恳求一个特定的资源时,会从服务器回来相同的硬编码内容。因而,例如,假如您在 /static/myproduct1.html 有一个关于产品的页面,则该页面将回来给每个用户。假如您添加另一个类似的产品到您的网站,您将需求添加另一个页面(例如 myproduct2.html )等。这或许开端变得十分低效:当您拜访数千个产品页面时会产生什么——你会在每个页面(根本的页面模板,结构等等)上重复许多代码,假如你想改动页面结构的任何东西,比方添加一个新的“相关产品”部分,有必要独自更改每个页面。

补白: 当你有少数页面时,向每个用户发送相同的内容时,静态网站是最佳挑选,然而随着页面数量的添加,它们的保护本钱也会很高。

让咱们回忆一下在上一篇文章中看到的静态网站架构图,看看它是怎么作业的。

客户端服务端交互概述

当用户想要导航到页面时,浏览器会发送一个指定 HTML 页面的 URL 的 HTTP 的GET恳求。 服务器从它的文件体系中检索所恳求的文档,并回来包括文档和 HTTP 呼应状况码“200 OK”(表明成功) 的 HTTP 呼应。服务器或许会回来一个不同的状况码,例如,”404 Not Found“表明文件不在服务器上,或许”301 Moved Permanently“表明假如文件存在,则被重定向到另一个位置。

静态站点的服务器只需求处理 GET 恳求,由于服务器不存储任何可修正的数据。它也不会依据 HTTP 恳求数据(例如 URL 参数或 cookie)更改呼应。

了解静态站点怎么作业在学习服务器端编程时十分有用,由于动态站点以完全相同的方法处理对静态文件 (CSS、JavaScript、静态图画等) 的恳求。

动态网站

动态站点能够依据特定的恳求 URL 和数据生成和回来内容 (而不是总是回来同一个 URL 的硬编码文件)。运用产品网页的示例,服务器将把产品“数据”存储在数据库中,而不是独自的 HTML 文件。当接纳到一个产品的 HTTP GET 恳求时,服务器将承认产品 ID,从数据库中获取数据,然后经过将数据插入到 HTML 模板中来结构呼应的 HTML 页面。与静态站点相比,这有很大的优势

经过运用数据库,能够有效地将产品信息存储在易于扩展、可修正和可查找的方法中。

运用 HTML 模板能够很容易地改动 HTML 结构,由于这只需求在一个模板中的某一处当地完结,而不需求跨越数千个静态页面。

剖析动态恳求

本节将逐步概述“动态”HTTP 恳求和呼应周期,以更详细的内容构建咱们在上一篇文章中所看到的内容。为了“让作业坚持实在”,咱们将运用一个体育团队司理网站的情形,在这个网站上,教练能够用 HTML 表单挑选他们的球队称号和球队规模,并为他们的下一场比赛中取得建议的“最佳阵容”。

下面的图表显示了“球队教练”网站的主要元素,以及当教练拜访他们的“最佳团队”列表时,操作序列的编号。使其动态的站点的部分是 Web 应用程序(这便是咱们将怎么引证处理 HTTP 恳求并回来 HTTP 呼应的服务器端代码)数据库,该数据库包括关于球员、球队、教练及其关系以及 HTML 模板的信息。

客户端服务端交互概述

在教练提交球员名单和球员人数后,其操作次序为:

  1. Web 浏览器运用资源的根本 URL(/best)来创立一个 HTTP GET恳求,将球队和球员编号附加到 URL 后边作为参数(例如 /best?team = my_team_name&show = 11)或作为 URL 地址的一部分(例如 /best/my_team_name/11/)。运用GET恳求是由于恳求仅仅获取数据(而不是修正数据)。
  2. Web 服务器检测到恳求是“动态的”,并将其转发给 Web 应用程序(Web Application)进行处理(Web 服务器依据其装备中界说的模式匹配规矩承认怎么处理不同的 URL)。
  3. Web 应用程序(Web Application)承认恳求的目的是依据 URL(/best/)取得“最佳团队列表”,并从 URL 中找出所需的球队称号和球员人数。然后,Web 应用程序(Web Application)从数据库中获取所需的信息(运用额定的“内部”参数来界说哪些球员是“最好”的,而且或许还从客户端 cookie 取得登录教练的身份)。
  4. Web 应用程序(Web Application)经过将数据(来自数据库)放入 HTML 模板中的占位符中动态地创立 HTML 页面。
  5. Web 应用程序(Web Application)将生成的 HTML(经过 Web 服务器)和 HTTP 状况代码 200(“成功”)回来到 Web 浏览器。假如有任何东西阻挠 HTML 被回来,那么 Web 应用程序将回来另一个状况代码 – 例如“404”来表明球队不存在。
  6. 然后,Web 浏览器将开端处理回来的 HTML,发送独自的恳求以获取其引证的任何其他 CSS 或 JavaScript 文件(请参阅进程 7)。
  7. Web 服务器从文件体系加载静态文件,并直接回来到浏览器(相同,正确的文件处理根据装备规矩和 URL 模式匹配)。

在服务器中,更新数据库中的记载的操作将被类似地与上述进程相同处理,可是更新数据库的这一类的操作,应该指定来自浏览器的 HTTP 恳求为POST恳求。

完结其他作业

Web 应用程序(Web Application)的作业是接纳 HTTP 恳求并回来 HTTP 呼应。尽管与数据库交互以获取或更新信息是十分常见的功用,可是代码也或许同时做其他作业,乃至不与数据库交互。

一个 Web 应用程序(Web Application)或许履行的额定使命的一个很好的比方便是发送一封电子邮件给用户,以承认他们在网站上的注册。该网站也或许履行日志记载或其他操作。

回来 HTML 以外的内容

服务器端网站代码并非只能在呼应中回来 HTML 代码片段/文件。它能够动态地创立和回来其他类型的文件(text,PDF,CSV 等)乃至是数据(JSON,XML 等)。

将数据回来到 Web 浏览器以便它能够动态更新自己的内容(AJAX)的想法实现现已有适当长的一段时间了。最近,“单页面应用程序”现已变得流行起来,整个网站用一个 HTML 文件编写,在需求时动态更新。运用这种风格的应用程序创立的网站将许多的计算本钱从服务器推向网络浏览器,并或许导致网站表现出更像本地应用程序(高度呼应等)。

web 结构简化服务器端的 web 编程

服务器端 web 结构使得编写处理咱们上面描绘的操作的代码变得简略得多。

web 结构能够供给的一个最重要的功用便是,供给简略的机制,以将不同的资源和页面定位到详细的处理函数。这使得坚持代码和各个不同形式的资源的联络变得简略。它也十分利于代码的保护,由于你能够直接改动在一个当地用来传输特定功用的 URL,而不必改动处理函数。

举个比方,咱们来思考一下下面的 Django(python) 代码,这些代码将两个 URL 地址定位到两个页面。榜首个地址确保了,一个包括了 /best/ URL 的 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, or RE) 的字符匹配机制。在这儿,你还不需求知道正则表达式是怎么作业的,除了要知道它们是怎么答应咱们在 URL 中匹配到字符的 (而不是像上面的硬编码) 而且知道怎么在咱们的视图函数中将它们用作参数。举个比方,一个真正简略的正则表达式或许会说“匹配一个大写字母,后边跟着 4 到 7 个小写字母”。

Web 结构还能够轻松地运用检查函数,从数据库获取信息。咱们的数据结构是在模型中界说的,模型是界说要存储在底层数据库中的字段的 Python 类。假如咱们有一个名为 Team 的模型,其中有一个“team_type”字段,那么咱们能够运用一个简略的查询语法来取回一切具有特定类型的球队。

下面的比方得到了一切字段 team_type(区别大小写)为“junior”的一切球队的列表 – 留意格局:字段称号(team_type),后边跟着双下划线,然后是运用的匹配类型)。还有许多其他的匹配类型,咱们能够组合他们。咱们也能够控制回来结果的次序和数量。

#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,一个 HTML 模板和一个界说要包括在模板中的信息的“context”目标。 render()函数是一个方便的函数,它运用上下文和 HTML 模板生成 HTML,并将其回来到 HttpResponse 目标中

显然地 web 结构能够协助你处理许多问题。咱们在下一篇文章里将会许多评论这些好处和一些流行的 web 结构。

总结

到这儿你应该关于服务器端代码不得不进行的操作有一个全体上的了解,而且知道一个服务器端 web 结构是从那些方面让这些变得更简略的。