對于整體布局而言,主要的頁面都在 ViewPager 當中,所以我們需要為不同結構的 Page 編寫不同的頁面,由于本例中每個 Page 的頁面結構都一樣,所以可以直接復用一套,直接在里面放置一個 ImageView 用于展示類別圖片。<?xml version="1.0" encoding="utf-8"?><ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" />
前端訪問網址形式:GET http://127.0.0.1/api/students/?page=4可以在子類中定義的屬性:page_size :每頁數目;page_query_param :前端發送的頁數關鍵字名,默認為"page";page_size_query_param :前端發送的每頁數目關鍵字名,默認為None;max_page_size :前端最多能設置的每頁數量。from rest_framework.pagination import PageNumberPaginationclass StandardPageNumberPagination(PageNumberPagination): page_size_query_param = 'page_size' # 每頁數據條數 max_page_size = 10class StudentViewSet(ModelViewSet): queryset = StudentsModel.objects.all() serializer_class = StudentsSerializer pagination_class = StandardPageNumberPagination
由于 PopupWindow 需要設置一個 View 樣式,所以除了 Activity 之外還要給 PopupWindow 增加一個布局。3.1.1 Activity 的布局布局文件非常簡單,甚至可以沿用上一節 AlertDialog 的布局,只需要在屏幕中央放置一個 Button 用于觸發 PopupWindow 即可,如下:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:padding="10dp" > <Button android:id="@+id/show" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="彈出一個PopupWindow" /></LinearLayout>3.1.2 PopupWindow 的布局PopupWindow 的布局大家可以根據自己的需求任意定義,沒有什么特別的要求,也體現了 PopupWindow 的靈活性,這里就放置一個 TextView 和一個 Button 用于關閉,如下:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="#000" android:padding="10dp"> <TextView android:textSize="20sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="底部彈出的PopupWindow" android:textColor="@android:color/holo_red_dark"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="關閉" android:id="@+id/close"/></LinearLayout>
當一個超鏈接在文章中反復出現時,可以使用全局聲明的形式,減少文章編寫的工作量。實例 3:#### 聲明超鏈接的細節[天壇][tiantan]公園,是明清兩代皇帝每年祭天和祈禱五谷豐收的地方。[天壇][tiantan]以嚴謹的建筑布局、奇特的建筑構造和瑰麗的建筑裝飾著稱于世。[tiantan]: http://www.tiantanpark.com渲染結果如下:實例 4:超鏈接聲明的另一種形式。#### 聲明超鏈接的細節[天壇][]公園,是明清兩代皇帝每年祭天和祈禱五谷豐收的地方。[天壇][]以嚴謹的建筑布局、奇特的建筑構造和瑰麗的建筑裝飾著稱于世。[天壇]: http://www.tiantanpark.com其渲染效果如下:全局的聲明可以寫在文章的任何地方,通常情況下,我們將它寫在整篇文章的結尾處。
打開 prometheus web UI 頁面 http://127.0.0.1:9090,點擊 alert 標簽頁,查看監控告警狀態:我們將監控的容器 cadvisor 關掉。docker stop cadvisor幾秒后刷新頁面,發現告警進入 Pending 暫掛狀態:一分鐘后(rule_1.yml 中 for = 1m 配置)告警進入 firing 狀態。查收告警郵件:修復故障后恢復正常:docker start cadvisor
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> { @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if(msg instanceof HttpRequest) { //1.打印瀏覽器的請求地址 System.out.println("客戶端地址:" + ctx.channel().remoteAddress()); //2.給瀏覽器發送的信息,封裝成ByteBuf ByteBuf content = Unpooled.copiedBuffer("hello world", CharsetUtil.UTF_8); //3.構造一個http的相應,即 httpresponse FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); //4.設置響應頭信息-響應格式 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); //5.設置響應頭信息-響應數據長度 response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); //6.將構建好 response返回 ctx.writeAndFlush(response); } }}代碼說明:瀏覽器發送過來的數據,被 Netty 給封裝成了 HttpObject 對象,我們需要判斷 HttpObject 具體所屬類型是不是 HttpRequest; 請求信息: 可以打印瀏覽器的請求信息,比如:請求地址、請求方式、請求體內容、請求頭內容等;響應信息: 給瀏覽器響應,必須構造 HttpResponse 對象,并且可以設置響應頭信息、響應體信息。特殊說明:如果不嚴格按照 Http 響應格式進行輸出,瀏覽器是無法讀取服務端的響應。
在 Django 工程中,由于視圖有兩種:FBV 和 CBV,因此視圖加裝飾器的情況也分為兩種:給視圖函數加裝飾器和給視圖類加裝飾器。由于視圖函數是普通的 Python 函數,因此給視圖函數加裝飾器和給普通函數加裝飾器方式一致。下面代碼中我們給視圖函數 index 加了一個簡單的裝飾器,用于在執行視圖函數前和后各打印一段字符:from django.shortcuts import render, HttpResponse, redirectdef wrapper(f): def innser(*args, **kwargs): print('before') ret = f(*args, **kwargs) print('after') return ret return innser @wrapperdef index(request): return render(request, 'index.html')由于類中的方法與普通函數不完全相同,因此不能直接將函數裝飾器應用于類中的方法 ,我們需要先將其轉換為方法裝飾器。Django 中提供了 method_decorator 裝飾器用于將函數裝飾器轉換為方法裝飾器:# 定義函數裝飾器def wrapper(f): def innser(*args, **kwargs): print('before') ret = f(*args, **kwargs) print('after') return ret return innser# 另一個代碼文件中使用wrapper裝飾器from django.views import Viewfrom django.utils.decorators import method_decorator@method_decorator(wrapper, name='get')class HelloView(View): # @method_decorator(wrapper) def get(self, request, *args, **kwargs): print('get') return HttpResponse('get\n') def post(self, request, *args, **kwargs): print('post') return HttpResponse('post\n') def put(self, request, *args, **kwargs): print('put') return HttpResponse('put\n') def delete(self, request, *args, **kwargs): print('delete') return HttpResponse('delete\n') @csrf_exempt # @method_decorator(wrapper) def dispatch(self, request, *args, **kwargs): return super(HelloView, self).dispatch(request, *args, **kwargs)對于給 View 類添加裝飾器,我們有如下幾種性質:將 method_decorator 裝飾器直接添加到 View 類上。第一個參數指定需要添加的裝飾器,如 wrapper,name 參數可以選擇將裝飾器 wrapper 作用到 View 類中的哪個函數。給類添加裝飾器時,必須要指定 name 參數,不然運行 Django 服務時會報錯;method_decorator 裝飾器可以直接作用于 View 類中的函數上。如果是在 get、post 這類 HTTP 請求方法的函數上,則裝飾器只會作用于調用該函數的 http 請求上;如果 method_decorator 裝飾器作用于 dispatch 函數上。由于對于視圖中所有的 HTTP 請求都會先調用 dispatch 方法找到對應請求方法的函數,然后再執行。所以這樣對應視圖內的所有 HTTP 請求方式都先經過裝飾器函數處理;
通過前面描述我們看到,要實現「記住我」功能,關鍵在于如何安全的保護好用戶的認證信息 Token。Spring Security 提供了兩種「記住我」的實現方式:使用 Hash 算法加密認證信息形成 Token,并將其保存在客戶端中;將認證信息保存在數據庫中,并將查詢條件保存在客戶端中。3.1.1 基于 Hash 的方式基于 Hash 的方式是一種相對簡單的集成方式。這種方式利用 Hash 的特性,將「記住我」信息進行存檔。每當用戶認證通過,服務端便生成一條 Hash 記錄,并發送給客戶端瀏覽器,其中內容包括「用戶名」、「Token 過期時間」、「密碼」、「簽名秘鑰」。發送的具體內容為:base64(username + ":" + expirationTime + ":" + md5Hex(username + ":" + expirationTime + ":" password + ":" + key))username: 根據 UserDetailsService 配置得到用戶名信息。password: 認證密碼,確保 UserDetailsService 中可以匹配到目標用戶。expirationTime: 「記住我」Roken 的有效期,精確到毫秒。key: 用于給 Token 簽名的密鑰信息,防止該 Token 被篡改。發送出的 Token 只有到用戶下次需要登錄時才會被使用到,這期間,需要確保用戶名、密碼、密鑰等信息不被改變。還需要注意的是,「記住我」Token 在過期之前,可以在任何地方使用,因此其安全性上有一定的問題,如果使用數字認證一樣。當用戶認為自己的 Token 不在安全時,最好的辦法是立刻改變自己的認證密碼,并且使全部的「記住我」Token 失效。啟動「記住我」功能僅需要一行配置,具體方式為:<http>...<remember-me key="簽名密鑰"/></http>當有多個 UserDetailsService 實例時,可以通過 user-service-ref 屬性指定唯一實例。3.1.2 基于存儲的方式使用數據庫作為 Token 存儲方式,需要在 <remember-me> 配置中增加 data-source-ref 屬性,配置方式如下:<http>...<remember-me data-source-ref="數據源實例"/></http>所用到的數據源需要包含 persistent_logins 數據表,其結構如下:create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)
Http 協議根據場景約定了一系列請求返回的狀態碼,方便對請求結果進行細粒度管理。該狀態碼由互聯網號碼分配局維護管理。狀態碼是由3位數字組成,目前總共分為 5 大類,在接下來的章節中將逐一詳細介紹。
為了在 HTTP 請求中攜帶 CSRF Token,我們必須要對 HTTP Request 做一些配置,因為它默認是不會攜帶 CSRF 相關參數的。默認情況下,Spring Security 中有 CsrfFilter 判斷請求中是否有 _csrf 參數,通常請求來自于兩種情況,Form 表單提交或者 Ajax。4.3.1 Form 表單提交使用 Form 表單提交代碼時,我們需要在 Form 參數中增加一個隱藏項:_csrf,例如:<input type="hidden" name="_csrf" value="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>這里的 _csrf 有幾種配置方式:自動注入Spring Security 通過擴展 Spring 的 RequestDataValueProcessor 類,實現了 RequestDataValueProcessor 類,這意味著如果我們使用 Spring 標簽庫、Thymeleaf 模板插件、或者其它集成了 RequestDataValueProcessor 對象的視圖組件是,表單的非冪等請求(例如:POST)都會自動攜帶 CSRF Token。JSP 標簽針對 JSP 作為頁面開發基礎,我們可以直接使用 Spring 的表單標簽庫或者 CsrfInput 標簽。也可以通過更加直接的方式,在使用 HttpServletRequest 屬性 _csrf,代碼如下:<c:url var="logoutUrl" value="/logout"/><form action="${logoutUrl}" method="post"><input type="submit" value="登出" /><input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/></form>4.3.2 Ajax 和 JSON 請求如果使用 Javascript 做為請求提交方式,我們沒法直接使用 Http CSRF 參數,取而代之的是使用 Http 頭的方式。這同樣也有幾種方法:自動注入Spring Security 可以自動將 CSRF Token 保存到 Cookie 中,一些客戶端框架如 AngularJS 會自動從中得到 CSRF Token 并放置到請求頭中。Meta 標簽另一種方式是從 Cookie 中解壓 Token 并使用 Meta 標簽,如下:<html><head> <meta name="_csrf" content="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/> <meta name="_csrf_header" content="X-CSRF-TOKEN"/> <!-- ... --></head>當 Meta 標簽中有 Token 信息時,我們就可以將 Meta 中的 CSRF Token 值用作請求參數了。以 JQuery 為例:$(function () { var token = $("meta[name='_csrf']").attr("content"); var header = $("meta[name='_csrf_header']").attr("content"); $(document).ajaxSend(function(e, xhr, options) { xhr.setRequestHeader(header, token); });});
今天我們簡單了解了下 Nginx 的配置文件以及相應的語法規則。但是我們僅僅簡單介紹了 Nginx 一些簡單的語法并完成了幾個簡單的案例,接下來我們將簡單學習 Nginx 的 Http 配置以及反向代理等常用配置。
本節主要從域名、版本、路徑、HTTP動詞、過濾信息、狀態碼、錯誤信息、返回結果、超媒體鏈接、數據格式 10 個方面介紹了 RESTful 設計方法和設計規范。為了讓更多的人方便使用所設計的 API 接口,以上規范一定要遵守哦!
在啟動類上添加 @EnableAdminServer 注解開啟 Spring Boot Admin 監控管理功能,代碼如下:實例:@SpringBootApplication@EnableAdminServer // 開啟監控管理public class SpringBootMonitorManagerApplication { public static void main(String[] args) { SpringApplication.run(SpringBootMonitorManagerApplication.class, args); }}然后運行啟動類,訪問 http://127.0.0.1:8080 會發現界面上已經顯示監控信息了。Spring Boot Admin 監控管理頁面
在配置好 Nexus 之后,我們要在項目中使用私服要如何使用呢?答案是,和使用其他的倉庫沒有太大區別。接下來,我們來具體介紹一下如何在項目中使用。打開 Maven 的 setting.xml 文件,將其中的 mirrors 節點和 profiles 節點改為如下配置;<mirrors> <mirror> <id>mic-maven</id> <mirrorOf>*</mirrorOf> <name>mic maven</name> <url>http://ip:port/nexus/content/groups/public/</url> </mirror></mirrors><profiles> <profile> <id>maven profile</id> <activation> <jdk>1.8</jdk> <activeByDefault>true</activeByDefault> </activation> <repositories> <repository> <id>chenyao-central</id> <name>chenyao maven</name> <url>http://ip:port/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>chenyao-central</id> <name>chenyao maven</name> <url>http://ip:port/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile></profiles><activeProfiles> <activeProfile>maven profile</activeProfile></activeProfiles>在 setting.xml 文件中配置好 Nexus 之后,我們可以在項目中引入一個 jar 包來試一下,如果能夠成功的將構件下載到本地,就說明我們的配置是正確的。介于我們在團隊內部使用的時候,還需要將項目的構建到 Nexus 中,所以,我們還需要進行單獨的配置。首先,我們在項目的 pom.xml 文件中,添加 distributionManagement 節點,用于控制分發管理;<distributionManagement> <repository> <id>mic-release</id> <name>mic maven</name> <url>http://ip:port/nexus/content/repositories/releases/</url> </repository> <snapshotRepository> <id>mic-snapshot</id> <name>mic maven</name> <url>http://ip:port/nexus/content/repositories/snapshots/</url> </snapshotRepository></distributionManagement>由于 Nexus 需要登陸才能使用,所以需要在 setting.xml 文件中配置服務器的登陸信息;<servers> <server> <id>mic-release</id> <username>admin</username> <password>admin123</password> </server> <server> <id>mic-snapshot</id> <username>admin</username> <password>admin123</password> </server></servers>配置完成后,我們在 mall-order目錄下執行mvn clean deploy;執行完之后,我們去 Nexus 中根據坐標可以查到這個構件。至此,我們已經能夠讓 Nexus 來代理中央倉庫,并且將我們自己的項目構建到私服中去,來提供給其他的項目中使用。
前邊提到 Localstorage 相比較 Cookie 的優勢是容量大和節省 HTTP 帶寬,但是它還是有自身的缺點,下邊羅列了它的缺點5M 容量依然小,用過數據庫的同學應該知道,MySQL 隨便一個表加上索引很容易超過 5M不能跨域名訪問,同一個網站可能會牽涉到子域名不能存儲關系型數據不能搜索
以上介紹了 Localstorage 和傳統離線存儲的優缺點對比,Localstorage 的使用方法以及項目實戰分析??偟膩碚f Localstorage 適用于業務簡單的輕量級存儲中,通過簡單的 API 操作增刪改查存儲鍵值對,而且可以通過事件監聽的方式獲取 Localstorage 的操作事件,無需發送 HTTP 請求,真正實現了離線存儲
創建 list.xml 布局文件,用來展示英雄的名稱、位置和描述:<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="5dp"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="17sp" android:textStyle="bold" /> <TextView android:id="@+id/designation" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/name" android:layout_marginTop="7dp" android:textColor="#343434" android:textSize="14dp" /> <TextView android:id="@+id/location" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/designation" android:layout_alignBottom="@+id/designation" android:layout_alignParentEnd="true" android:textColor="#343434" android:textSize="14sp" /></RelativeLayout>
所謂限定頭信息,指 Spring MVC 可以通過 HTTP 請求包中的消息頭信息進行過濾。如下面的實例:@RequestMapping(value="/test",headers="content-type=text/*")public String test(){ ... }test() 方法只會響應請求包中的內容類型為 text/* 的請求。無論是方法限定、還是參數限定或是頭信息限定,其本質都是檢查請求包是否符合條件要求。
本節通過一個具體的例子講解 after_request 與 teardown_request 的區別,代碼如下:from flask import Flask, request, render_templateapp = Flask(__name__)@app.route('/')def index(): print('execute request without error') return 'Hello World'@app.route('/error')def error(): print('execute request with error') 1 / 0 return 'Hello World'@app.after_requestdef after_request(response): print('after_request') return [email protected]_requestdef teardown_request(exception): print('teardown_request:', exception)if __name__ == '__main__': app.run()在第 5 行,訪問頁面 / 時執行函數 index(),該函數打印字符串 ‘execute request without error’,執行期間沒有發生異常。在第 10 行,訪問頁面 /error 時執行函數 error(),該函數打印字符串 ‘execute request with error’,執行期間發生異常。在第 13 行,人為的通過 1 / 0 引發除零異常。在第 16 行,注冊 after_request 鉤子函數,執行請求后會調用該鉤子函數。在第 21 行,注冊 teardown_request 鉤子函數,執行請求后都會調用該鉤子函數。鉤子函數的第一個參數是 exception 對象,指向執行請求時發生的錯誤。
爬蟲文件的命名一定要準確,爬蟲爬取的是哪一個網站就用哪一個網站來進行命名,這樣以后我們寫的爬蟲越來越多會方便管理。文件創建好之后首先導入 requests 第三方庫和頁面解析工具 BeautifulSoup:import requests # requests庫,用來發送網絡請求from bs4 import BeautifulSoup # 一個解析庫,用來解析網頁結構Tips:BeautifulSoup 我們在后面會講到,這里只是先用一下。
在真實的項目中會經常使用到 axios 這樣的 ajax 請求的庫,雖然可以直接使用,但是往往業務中會有很多接口請求的地方,而這么多的請求有些固定不變的,每個接口在請求時都需要,如:token,baseURL,timeout 等等,針對這樣的場景,我們可以對 axios 庫進行二次業務封裝。對于接口不同的返回結果我們希望有一個全局的提示框,這里我們使用 element-ui 組件庫搭配使用。封裝后的代碼如下:import axios from 'axios';import { baseURL } from '@/config'class Http { constructor(baseUrl) { this.baseURL = baseURL; this.timeout = 3000; } setInterceptor(instance) { instance.interceptors.request.use(config => { return config; }); instance.interceptors.response.use(res => { if (res.status == 200) { return Promise.resolve(res.data); } else { return Promise.reject(res); } }, err => { return Promise.reject(err); }); } mergeOptions(options) { return { baseURL: this.baseURL, timeout: this.timeout, ...options } } request(options) { const instance = axios.create(); const opts = this.mergeOptions(options); this.setInterceptor(instance); return instance(opts); } get(url, config = {}) { return this.request({ method: 'get', url: url, ...config }) } post(url, data) { return this.request({ method: 'post', url, data }) }}export default new Http;
在學習Socket編程之前我們要了解一下概念。端口不是物理設備,而是促進服務器和客戶端之間通信的抽象概念。端口是由一個 2 的 16 次冪的整數表示的,所以,一臺機器最多可以有65536個端口(0~65535)。端口一共分為三個種類:知名端口:0 ~ 1023(例如:80端口用于http,25端口用于smtp)。注冊端口:1024 ~ 49151。動態/私有端口:49152 ~ 65535。
本節主要介紹 Nginx 的進程模型以及介紹了 Master 和 Worker 之間的通信過程。此外,我們介紹了 Nginx 的事件驅動模型。異步、多路IO復用、非阻塞等特點早就了 Nginx 的高性能。接下來,我們完成了 Nginx 進程模型的幾個實驗,直觀體檢 Nginx 的進程模型。下一節將重點介紹 Nginx 模塊相關的內容,并手動實現一個簡單的 http 模塊。
本文主要使用了gin這個第三方開發包,來搭建了一個Go語言的web應用,這個gin包的本質還是http包,但是它在其上封裝了一層接口,使我們可以更高效的開發以及開發出來的應用更安全。在我們Go語言的學習和開發的過程中,在熟悉了官方庫之后,我們也可以去使用一些能更好的幫助我們開發的第三方包。
經過這一番折騰后,Spring MVC 項目的基礎架構就完成了,把項目部署到服務器(tomcat)中。查看 tomcat 啟動時的輸出日志中是否存在下面的信息。如果存在,表示 Spring MVC 項目初始化成功。在瀏覽器的地址欄中輸入:http://localhost:8888/sm-demo/Tips: 我的端口號是 8888。如果瀏覽器中輸出 Hello World ,恭喜,咱們取得了使用 Spring MVC 第一階段的成功。
State Drawables 用來描述一個 View 在不同狀態下的形態,我們可以給每一種狀態設置一中背景樣式,比如我們可以讓我們的 Button 在點擊、選擇和默認態下呈現不同的樣式:<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/button_pressed" android:state_pressed="true" /> <item android:drawable="@drawable/button_checked" android:state_checked="true" /> <item android:drawable="@drawable/button_default" /></selector>
產生原因:包管理器源在國外,網絡不好就很難打開甚至打不開。// 國外的源https://packagecontrol.io/channel_v3.json解決方案:設置國內源,步驟如下:Preferences > Package Settings > Package Control > Settings User,添加如下代碼并保存,解決。Tips: 如果你的電腦不能科學上網的話,這一步驟還是比較重要的,原因你懂的!類似 npm,google"channels": [ "http://packagecontrol.cn/channel_v3.json"]
本節內容我們主要介紹了如何向視圖函數傳送參數,包括兩種方式:通過動態的 URLconf 配置傳遞參數到視圖函數中;通過 http 請求帶參數傳遞給視圖函數。至此,Django 中的路由系統和視圖函數已經介紹完畢。接下來會介紹 Django 中的模板系統。
由于臨時的服務器維護或者過載,服務器當前無法處理請求。這個狀況是臨時的,并且將在一段時間以后恢復。如果能夠預計延遲時間,那么響應中可以包含一個 Retry-After 頭用以標明這個延遲時間。HTTP/1.1 503 Service UnavailableContent-Type text/plainRetry-After: 1800
是指在同一個連接中,不同的請求之間是沒有聯系的,這次的請求無法知道上次請求的上下文信息。但是,HTTP 又是有會話的,也就是說,我們可以通過 Cookies 來解決不同請求的上下文信息共享。Cookie 的具體內容,我們會在后面的章節進行描述。