第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
201 Created

請(qǐng)求已經(jīng)被實(shí)現(xiàn),而且有一個(gè)新的資源已經(jīng)依據(jù)請(qǐng)求的需要而建立,且其 URI 已經(jīng)隨 Location 頭信息返回。適用場(chǎng)景API 請(qǐng)求創(chuàng)建一個(gè)資源對(duì)象,返回了新資源對(duì)象的地址。目前開發(fā)中大部分是新增一個(gè)資源返回這個(gè)資源的 ID ,然后根據(jù) ID 再查詢?cè)斍?。Http 的很多狀態(tài)碼都定很細(xì),實(shí)踐中并不都那么遵守理論??蛻舳薖OST /add-article HTTP/1.1Content-Type: application/json{ "article": "http" }服務(wù)端HTTP/1.1 201 CreatedLocation: /article/01

5.1 根據(jù)需求制定 RESTful 風(fēng)格的接口文檔

既然是要做商品瀏覽頁面,將商品增刪改查都實(shí)現(xiàn)了就是了。 RESTful 風(fēng)格接口并不麻煩,一般情況下需要項(xiàng)目團(tuán)隊(duì)一起商量制定。此處我們指定如下:動(dòng)詞接口含義接口地址 GET 查詢商品 (id=1) 信息 http://127.0.0.1:8080/goods/1GET 查詢商品列表信息 http://127.0.0.1:8080/goodsPOST 新增商品 http://127.0.0.1:8080/goodsPUT 修改商品 (id=1) 信息 http://127.0.0.1:8080/goods/1DELETE 刪除商品 (id=1)http://127.0.0.1:8080/goods/1Tips: RESTful 風(fēng)格通過 HTTP 動(dòng)詞( GET / POST / PUT / DELETE )區(qū)分操作類型, URL 格式比較固定,僅此而已,非常簡(jiǎn)單。

下節(jié)預(yù)告

除了 HTML/CSSJS 的知識(shí)外,學(xué)習(xí) Web 開發(fā)還需要對(duì) HTTP 協(xié)議有一定的了解,HTTP 協(xié)議同樣是 Web 開發(fā)必備基礎(chǔ)知識(shí),下節(jié)課我們就來學(xué)習(xí)下 HTTP 協(xié)議以及 HTTP 在 Web 開發(fā)中所起到的作用。不僅如此,下節(jié)課會(huì)給給大家進(jìn)行一個(gè) Web 開發(fā)常見概念的普及,讓大家對(duì) Web 開發(fā)有一個(gè)更清晰的了解。

2. 在 Flask 中分析 URL 參數(shù)

服務(wù)端收到將客戶端發(fā)送的數(shù)據(jù)后,封裝形成一個(gè)請(qǐng)求對(duì)象,在 Flask 中,請(qǐng)求對(duì)象是一個(gè)模塊變量 flask.request,request 對(duì)象包含了眾多的屬性。假設(shè) URL 等于 http://localhost/query?userId=123,則與 URL 參數(shù)相關(guān)的屬性如下:屬性說明urlhttp://localhost/query?userId=123base_urlhttp://localhost/queryhostlocalhosthost_urlhttp://localhost/path/queryfull_path/query?userId=123下面編寫一個(gè) Flask 程序 request.py,打印 request 中和 URL 相關(guān)的屬性:#!/usr/bin/python3from flask import Flaskfrom flask import requestapp = Flask(__name__)def echo(key, value): print('%-10s = %s' % (key, value))@app.route('/query')def query(): echo('url', request.url) echo('base_url', request.base_url) echo('host', request.host) echo('host_url', request.host_url) echo('path', request.path) echo('full_path', request.full_path) print() print(request.args) print('userId = %s' % request.args['userId']) return 'hello'if __name__ == '__main__': app.run(port = 80)在第 10 行,定義路徑 /query 的處理函數(shù) query();在第 11 行到第 16 行,打印 request 對(duì)象中和 URL 相關(guān)的屬性;URL 中的查詢參數(shù)保存在 request.args 中,在第 20 行,打印查詢參數(shù) userId 的值。在瀏覽器中輸入 http://localhost/query?userId=123,F(xiàn)lask 程序在終端輸出如下:url = http://localhost/query?userId=123base_url = http://localhost/queryhost = localhosthost_url = http://localhost/path = /queryfull_path = /query?userId=123ImmutableMultiDict([('userId', '123')])userId = 123

1.3 服務(wù)端支持

服務(wù)器端需要對(duì)客戶端發(fā)起的 HTTP 請(qǐng)求做相應(yīng)的回復(fù),主要是將 HTTP 報(bào)文頭的 content-type 字段設(shè)置成 text/event-stream,下邊以 PHP 舉例:1129

1.4 server 指令

Syntax: server { ... }Default: —Context: http這里 server 的上下文環(huán)境是 http,這說明 server 指令塊只能出現(xiàn)在http指令塊中,否則會(huì)出錯(cuò)。server 指令塊中也是許多指令的集合,比如listen指令,表示監(jiān)聽 http 請(qǐng)求的端口,還有 server_name、root、index 等指令。...http { server { # 監(jiān)聽端口 listen 8089; server_name localhost; # 今天資源根路徑 root /data/yum_source; # 打開目錄瀏覽功能 autoindex on; # 指定網(wǎng)站初始頁,找index.html或者index.htm頁面 index index.html index.htm; } ...}...下面我們初步了解下 Nginx 的在一些場(chǎng)景下的配置,使用到的都是一些簡(jiǎn)單的配置指令。

4.9 開發(fā)商品控制器類

我們還是遵循之前的 RESTful 風(fēng)格,制定后端訪問接口如下:動(dòng)詞接口含義接口地址GET查詢商品(id=1)信息http://127.0.0.1:8080/goods/1GET查詢商品列表信息http://127.0.0.1:8080/goodsPOST新增商品http://127.0.0.1:8080/goodsPUT修改商品(id=1)信息http://127.0.0.1:8080/goods/1DELETE刪除商品(id=1)http://127.0.0.1:8080/goods/1我們根據(jù)上面的接口列表,實(shí)現(xiàn)控制器類代碼如下:實(shí)例:/** * 商品控制器類 */@RestControllerpublic class GoodsController { @Autowired private GoodsService goodsService; /** * 按id獲取商品信息 */ @GetMapping("/goods/{id}") public GoodsDo getOne(@PathVariable("id") long id) { return goodsService.getById(id); } /** * 獲取商品列表 */ @GetMapping("/goods") public List<GoodsDo> getList() { return goodsService.getList(); } /** * 新增商品 */ @PostMapping("/goods") public void add(@RequestBody GoodsDo goods) { goodsService.add(goods); } /** * 編輯商品 */ @PutMapping("/goods/{id}") public void update(@PathVariable("id") long id, @RequestBody GoodsDo goods) { // 修改指定id的博客信息 goods.setId(id); goodsService.edit(goods); } /** * 移除商品 */ @DeleteMapping("/goods/{id}") public void delete(@PathVariable("id") long id) { goodsService.remove(id); }}

2.1 創(chuàng)建 Spring Boot web 服務(wù)端應(yīng)用

工程目錄結(jié)構(gòu)如下:? OAuth2ResourceServer/ ? src/ ? main/ ? java/imooc/springsecurity/oauth2/server/ ? config/ OAuth2ResourceServerController.java # 配置控制器,用來扮演資源 OAuth2ResourceServerSecurityConfiguration.java # 資源服務(wù)器相關(guān)配置均在此處 OAuth2ResourceServerApplication.java # 啟動(dòng)類 ? resources/ application.yml # 配置 OAuth2.0 認(rèn)證服務(wù)器的地址等信息 ? test/ pom.xml在 pom.xml 文件中增加依賴項(xiàng),相比「用戶名密碼認(rèn)證實(shí)例」,此處注意添加了 OAuth2 自動(dòng)配置的相關(guān)依賴。spring-security-oauth2-autoconfigure 和 spring-security-oauth2-resource-server。完整 pom.xml 文件如下:<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>org.example</groupId> <artifactId>OAuth2ResourceServer</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-resource-server</artifactId> <version>5.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>創(chuàng)建 SpringSecurity OAuth2 資源服務(wù)器配置類,src/main/java/imooc/springsecurity/oauth2/server/OAuth2ResourceServerSecurityConfiguration.java。使其繼承 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter 類,并其增加 @EnableResourceServer 標(biāo)簽,以聲明此類作為 OAuth2 資源服務(wù)器的配置依據(jù);在 configure(HttpSecurity http) 方法中配置其資源的訪問權(quán)限,本例中默認(rèn)所有資源需要認(rèn)證用戶才能訪問;完整代碼如下:package imooc.springsecurity.oauth2.server.config;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;@Configuration@EnableResourceServerpublic class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated() ) .csrf().disable(); }}在 application.yml 文件中,需要將 OAuth2.0 認(rèn)證服務(wù)器的信息配置進(jìn)去。server: port: 8081security: oauth2: client: client-id: reader # 客戶端標(biāo)識(shí),與認(rèn)證服務(wù)器中的寫法相同 client-secret: secret # 客戶端秘鑰,與認(rèn)證服務(wù)器中的寫法相同 user-authorization-uri: http://localhost:8080/oauth/authorize # 客戶端鑒權(quán)地址 access-token-uri: http://localhost:8080/oauth/token # 客戶端獲取 Token 地址 resource: id: reader # 資源服務(wù)器標(biāo)識(shí),這里可以根據(jù)業(yè)務(wù)情況填寫 token-info-uri: http://localhost:8080/oauth/check_token # 驗(yàn)證 Token 的地址至此,資源服務(wù)器的核心內(nèi)容均配置完成。

206 Partial Content

客戶端對(duì)服務(wù)端的資源進(jìn)行了某一部分的請(qǐng)求,服務(wù)端正常執(zhí)行,響應(yīng)報(bào)文中包含由 Content-Range 指定范圍的實(shí)體內(nèi)容??蛻舳薌ET /imooc/video.mp4 HTTP/1.1Range: bytes=1048576-2097152服務(wù)端HTTP/1.1 206 Partial ContentContent-Range: bytes 1048576-2097152/3145728Content-Type: video/mp4

4. 案例演示

我們?cè)?nginx.conf 中添加如下的日志配置:...http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; map $status $loggable { ~^[34] 0; default 1; } access_log logs/access.log main if=$loggable; server { listen 8000; return 200 '8000, server\n'; } server { listen 8001; return 300 '8001, server\n'; } server { listen 8002; return 401 '8002, server\n'; } ... }...這里我們綜合了前面涉及的知識(shí),這里只簡(jiǎn)單測(cè)試日志配置中 if 功能。我們?cè)O(shè)置請(qǐng)求的相應(yīng)碼為 3xx 和 4xx 時(shí),日志不會(huì)記錄。接下來,啟動(dòng)或者熱加載 Nginx, 然后分別對(duì)應(yīng)三個(gè)端口發(fā)送 http 請(qǐng)求并觀察 access.log 日志:[shen@shen ~]$ curl http://180.76.152.113:8000 -IHTTP/1.1 200 OKServer: nginx/1.17.6Date: Tue, 04 Feb 2020 13:31:03 GMTContent-Type: application/octet-streamContent-Length: 13Connection: keep-alive[shen@shen ~]$ curl http://180.76.152.113:8001 -IHTTP/1.1 300 Server: nginx/1.17.6Date: Tue, 04 Feb 2020 13:31:06 GMTContent-Type: application/octet-streamContent-Length: 13Connection: keep-alive[shen@shen ~]$ curl http://180.76.152.113:8002 -IHTTP/1.1 401 UnauthorizedServer: nginx/1.17.6Date: Tue, 04 Feb 2020 13:31:08 GMTContent-Type: application/octet-streamContent-Length: 13Connection: keep-alive# 到 Nginx 主機(jī)上觀察 access.log 日志,發(fā)現(xiàn)只有響應(yīng)碼為200的請(qǐng)求記錄了日志[root@server nginx]# tail -f logs/access.log171.82.186.225 - - [04/Feb/2020:21:33:24 +0800] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.29.0" "-"

4.1 Maven 文檔配置

這一段配置代碼,其實(shí)是固定的格式,表示當(dāng)前文檔是 Maven 配置文檔。實(shí)例:<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion></project>

1.3 返回?cái)?shù)據(jù)

根據(jù)業(yè)務(wù)處理完獲得返回實(shí)體數(shù)據(jù),然后遵從 Http 協(xié)議格式構(gòu)造返回的消息報(bào)文。瀏覽器獲得到的數(shù)據(jù)也會(huì)根據(jù) Http 協(xié)議進(jìn)行渲染。

4.2 編寫布局

菜單本身并不涉及到布局的編寫,我們只需要兩個(gè) View,一個(gè)綁定給 Context Menu,一個(gè)給 Popup Menu:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/tv_context" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="30dp" android:text="我這里有 Context Menu" android:textSize="20sp" /> <Button android:id="@+id/bt_popup" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="pop" android:text="我這里有 Popup Menu" /></LinearLayout>

1.5 method 屬性

使用表單提交數(shù)據(jù)時(shí),實(shí)際上只發(fā)送一個(gè) HTTP 協(xié)議的數(shù)據(jù)請(qǐng)求,HTTP 協(xié)議有很多種數(shù)據(jù)請(qǐng)求方式,這個(gè) method 屬性用于設(shè)定 HTTP 請(qǐng)求的方式。常用的方式有 post、get,當(dāng)未設(shè)置時(shí)默認(rèn)使用 get 方式。除了常用方式之外,根據(jù)服務(wù)器 HTTP 網(wǎng)關(guān)的設(shè)置,還可以支持:options 客戶端查看服務(wù)器的配置;head 用于獲取報(bào)文頭,沒有 body 實(shí)體;delete 請(qǐng)求服務(wù)器刪除指定頁面;put 請(qǐng)求替換服務(wù)器端文檔內(nèi)容;trace 用于診斷服務(wù)器;connect 將連接設(shè)置成管道方式的代理服務(wù)器,用于 HTTP1.1

websocket

網(wǎng)頁中的絕大多數(shù)請(qǐng)求使用的是 HTTP 協(xié)議,HTTP 是一個(gè)無狀態(tài)的應(yīng)用層協(xié)議,它有著即開即用的優(yōu)點(diǎn),每次請(qǐng)求都是相互獨(dú)立的,這對(duì)于密集程度較低的網(wǎng)絡(luò)請(qǐng)求來說是優(yōu)點(diǎn),因?yàn)闊o需創(chuàng)建請(qǐng)求的上下文條件,但是對(duì)于密集度或者實(shí)時(shí)性要求較高的網(wǎng)絡(luò)請(qǐng)求(例如 IM 聊天)場(chǎng)景來說,可能 HTTP 會(huì)力不從心,因?yàn)槊縿?chuàng)建一個(gè) HTTP 請(qǐng)求對(duì)服務(wù)器來說都是一個(gè)很大的資源開銷。這時(shí)我們可以考慮一個(gè)相對(duì)性能較高的網(wǎng)絡(luò)協(xié)議 Socket,他的網(wǎng)頁版本被稱為 Websocket。

2.6 跟蹤訪問行為

運(yùn)行啟動(dòng)類,訪問 http://127.0.0.1:8080/login?username=imooc&password=123,控制臺(tái)輸出如下:控制臺(tái)輸出內(nèi)容可見我們已經(jīng)完整的跟蹤了一次對(duì) http://127.0.0.1:8080/login 接口的訪問。

1. 前言

上節(jié)我們討論了 Spring Security 如何防范 CSRF 攻擊,本節(jié)我們討論如何用最簡(jiǎn)單的方式提升 Spring Security Web 項(xiàng)目的安全性。Spring Security 可以通過「HTTP 安全響應(yīng)頭」的方式提升安全性。本節(jié)我們討論如何實(shí)現(xiàn) HTTP 安全響應(yīng)頭。

4.2 首頁布局

HTTPURLConnection 需要一個(gè)觸發(fā)時(shí)機(jī),所以在首頁布局上我們放置一個(gè) Button 用于觸發(fā) http 請(qǐng)求:<?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:orientation="vertical"> <Button android:id="@+id/start_http" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="100dp" android:text="發(fā)起 Http 請(qǐng)求" /></LinearLayout>

2. 關(guān)于 HTTP 防火墻

Servlet 規(guī)范中已經(jīng)為 HttpServletRequest 定義了一些屬性,這些屬性通過 Getter 方法訪問,并用作匹配處理。這些屬性包括:contextPath、servletPath、pathInfo 和 queryString。Spring Security 僅關(guān)心應(yīng)用程序的路徑部分,并不關(guān)心 contextPath。另一方面,在 Servlet 的規(guī)范中,缺少對(duì) servletPath 和 pathInfo 的規(guī)定,比如 URL 中每個(gè)路徑段都可能包含參數(shù),然而這些參數(shù)是否應(yīng)該算作 servletPath 或者 pathInfo 值中,規(guī)范卻沒有明確說明,并且在不同的 Servlet 容器中,其處理行為也不盡相同。當(dāng)應(yīng)用程序被部署在不從路徑中解析參數(shù)的容器中時(shí),攻擊者可能將路徑參數(shù)添加到請(qǐng)求的 URL 中,從而導(dǎo)致模式匹配的成功或者失敗。還有另一種情況,路徑中可能包含一些如遍歷 /../ 或者多個(gè)連續(xù)正斜杠 // 此類的內(nèi)容,這也可能導(dǎo)致模式匹配的失效。有的容器在執(zhí)行 Servlet 映射之前對(duì)其做了規(guī)范化處理,但不是所有容器都是。默認(rèn)情況下,這些容器會(huì)自動(dòng)拒絕未規(guī)范化的請(qǐng)求,并刪除路徑參數(shù)和重復(fù)斜杠。所以,為了保證程序在不同環(huán)境的一致性,我們就需要使用 FilterChainProxy 來管理安全過濾器鏈。還要注意一點(diǎn),servletPath 和 pathInfo 是由容器解析得出的,因此我們還要避免使用分號(hào)。路徑的默認(rèn)匹配策略使用了 Ant 風(fēng)格,這也是最為常用的一種匹配模式。這個(gè)策略是由類 AntPathRequestMatcher 實(shí)現(xiàn)的,在 Spring 中由 AntPathMatcher 負(fù)責(zé)對(duì) servletPath 和 pathInfo 屬性執(zhí)行不區(qū)分大小寫的模式匹配,此過程中不處理 queryString。有時(shí)候,我們會(huì)需要更復(fù)雜的匹配策略,比如正則表達(dá)式,這時(shí)候就需要用到 RegexRequestMatcher 對(duì)象了。URL 匹配并不適合作為訪問控制的唯一策略,我們還需要在服務(wù)層使用方法安全性來確保其安全性。由于 URL 是富于變化的,所以我們很難涵蓋所有情況,最好的辦法是采用白名單方式,只允許確認(rèn)可用的地址被訪問。

HTTP 協(xié)議狀態(tài)碼-4XX

4XX 的狀態(tài)碼指的是請(qǐng)求出錯(cuò)了,而且很有可能是客戶端側(cè)的異常??蛻舳藗?cè)的異常很多,有時(shí)候情況也比較復(fù)雜,下面定義的狀態(tài)碼有時(shí)候也只能反應(yīng)一個(gè)大概情況,而不一定確切的。

3.1 串行獲取 <a href="http://baidu.com">baidu.com</a>、<a href="http://taobao.com">taobao.com</a>、<a href="http://qq.com">qq.com</a> 首頁

編寫程序 serial.py,該程序以串行的方式獲取 baidu、taobao、qq 的首頁,內(nèi)容如下:from datetime import datetimeimport requestsimport threadingdef fetch(url): response = requests.get(url) print('Get %s: %s' % (url, response))time0 = datetime.now()fetch("https://www.baidu.com/")fetch("https://www.taobao.com/")fetch("https://www.qq.com/")time1 = datetime.now()time = time1 - time0print(time.microseconds)在第 5 行,定義了函數(shù) fetch,函數(shù) fetch 獲取指定 url 的網(wǎng)頁。在第 6 行,調(diào)用 requests 模塊的 get 方法獲取獲取指定 url 的網(wǎng)頁。在第 9 行,記錄執(zhí)行的開始時(shí)間。在第 11 行到第 13 行,串行執(zhí)行獲取 baidu、taobao、qq 的首頁。在第 15 行到第 17 行,記錄執(zhí)行的結(jié)束時(shí)間,并計(jì)算總共花費(fèi)的時(shí)間,time.micoseconds 表示完成需要的時(shí)間(微秒)。執(zhí)行 serial.py,輸出如下:Get https://www.baidu.com/: <Response [200]>Get https://www.taobao.com/: <Response [200]>Get https://www.qq.com/: <Response [200]>683173在輸出中,<Response [200]> 是服務(wù)器返回的狀態(tài)碼,表示獲取成功。成功獲取了 baidu、taobao、qq 的首頁,總共用時(shí)為 683173 微秒。

2.2 101 Switching Protocols

服務(wù)器將遵從客戶的請(qǐng)求轉(zhuǎn)換到另外一種協(xié)議。常見的就是 Websocket 連接??蛻舳薌ET /websocket HTTP/1.1Host: www.imocc.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13客戶端請(qǐng)求要將原本是 HTTP/1.1 協(xié)議升級(jí)成 Websocket 協(xié)議。服務(wù)端HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: Upgrade服務(wù)端返回 101 代表協(xié)議轉(zhuǎn)換成功。

3.3 測(cè)試

首先直接請(qǐng)求 http://127.0.0.1:8080/info ,由于此時(shí)未登錄,所以請(qǐng)求被攔截,網(wǎng)頁輸出如下:訪問被攔截如果先請(qǐng)求登錄方法 http://127.0.0.1:8080/login?username=imooc&password=123 ,然后訪問 http://127.0.0.1:8080/info ,則網(wǎng)頁輸出:登錄成功后,訪問正常通過攔截器

3.2 代碼集成

開啟 saml2Login() 支持;@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .saml2Login() // 啟動(dòng) SAML2 認(rèn)證支持 ; }}為 SAML 2.0 認(rèn)證配置認(rèn)證環(huán)境;@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .saml2Login() .relyingPartyRegistrationRepository(...) // 配置認(rèn)證環(huán)境 ; }}在 SAML 2.0 中,SP 和 IDP 都是作為可信成員,將其映射保存在 RelyingPartyRegistration 對(duì)象中,RelyingPartyRegistration 對(duì)象通過 HttpSecurity 實(shí)例中的 .saml2Login().relyingPartyRegistrationRepository() 方法實(shí)現(xiàn)其數(shù)值配置。至此,最基礎(chǔ)的 SAML 2.0 的認(rèn)證配置就已經(jīng)完成了。

3.1 重定向到 HTTPS

當(dāng)客戶端使用 HTTP 向服務(wù)端發(fā)送請(qǐng)求時(shí),Spring Security 可以將請(qǐng)求自動(dòng)轉(zhuǎn)換為 HTTPS 的連接方式。例如,如下代碼強(qiáng)制所有 HTTP 請(qǐng)求重定向?yàn)?HTTPS 請(qǐng)求:@Configuration@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) { http.requiresChannel(channel -> channel.anyRequest().requiresSecure()); }}

2.2 meta 的屬性

name 描述網(wǎng)頁content 方便搜索引擎查找和分類http-equiv http文件頭設(shè)置

3. 圖書爬蟲之代碼實(shí)現(xiàn)

根據(jù)上面的分析,我們來實(shí)現(xiàn)相應(yīng)的代碼。首先是完成獲取計(jì)算機(jī)的所有分類以及相應(yīng)的 URL 地址:def get_all_computer_book_urls(page_url): """ 獲取所有計(jì)算機(jī)分類圖書的url地址 :return: """ response = requests.get(url=page_url, headers=headers) if response.status_code != 200: return [], [] response.encoding = 'gbk' tree = etree.fromstring(response.text, etree.HTMLParser()) # 提取計(jì)算機(jī)分類的文本列表 c = tree.xpath("http://div[@id='wrap']/ul[1]/li[@class='li']/a/text()") # 提取計(jì)算機(jī)分類的url列表 u = tree.xpath("http://div[@id='wrap']/ul[1]/li[@class='li']/a/@href") return c, u我們簡(jiǎn)單測(cè)試下這個(gè)函數(shù):[store@server2 chap06]$ python3Python 3.6.8 (default, Apr 2 2020, 13:34:55) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linuxType "help", "copyright", "credits" or "license" for more information.>>> from china_pub_crawler import get_all_computer_book_urls>>> get_all_computer_book_urls('http://www.china-pub.com/Browse/')(['IT圖書網(wǎng)絡(luò)出版 [59-00]', '計(jì)算機(jī)科學(xué)理論與基礎(chǔ)知識(shí) [59-01]', '計(jì)算機(jī)組織與體系結(jié)構(gòu) [59-02]', '計(jì)算機(jī)網(wǎng)絡(luò) [59-03]', '安全 [59-04]', '軟件與程序設(shè)計(jì) [59-05]', '軟件工程及軟件方法學(xué) [59-06]', '操作系統(tǒng) [59-07]', '數(shù)據(jù)庫(kù) [59-08]', '硬件與維護(hù) [59-09]', '圖形圖像、多媒體、網(wǎng)頁制作 [59-10]', '中文信息處理 [59-11]', '計(jì)算機(jī)輔助設(shè)計(jì)與工程計(jì)算 [59-12]', '辦公軟件 [59-13]', '專用軟件 [59-14]', '人工智能 [59-15]', '考試認(rèn)證 [59-16]', '工具書 [59-17]', '計(jì)算機(jī)控制與仿真 [59-18]', '信息系統(tǒng) [59-19]', '電子商務(wù)與計(jì)算機(jī)文化 [59-20]', '電子工程 [59-21]', '期刊 [59-22]', '游戲 [59-26]', 'IT服務(wù)管理 [59-27]', '計(jì)算機(jī)文化用品 [59-80]'], ['http://product.china-pub.com/cache/browse2/59/1_1_59-00_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-01_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-02_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-03_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-04_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-05_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-06_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-07_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-08_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-09_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-10_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-11_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-12_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-13_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-14_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-15_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-16_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-17_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-18_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-19_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-20_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-21_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-22_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-26_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-27_0.html', 'http://product.china-pub.com/cache/browse2/59/1_1_59-80_0.html'])可以看到這個(gè)函數(shù)已經(jīng)實(shí)現(xiàn)了我們想要的結(jié)果。接下來我們要完成一個(gè)函數(shù)來獲取對(duì)應(yīng)分類下的所有圖書信息,不過在此之前,我們需要先完成解析單個(gè)圖書列表頁面的方法:def parse_books_page(html_data): books = [] tree = etree.fromstring(html_data, etree.HTMLParser()) result_tree = tree.xpath("http://div[@class='search_result']/table/tr/td[2]/ul") for result in result_tree: try: book_info = {} book_info['title'] = result.xpath("./li[@class='result_name']/a/text()")[0] book_info['book_url'] = result.xpath("./li[@class='result_name']/a/@href")[0] info = result.xpath("./li[2]/text()")[0] book_info['author'] = info.split('|')[0].strip() book_info['publisher'] = info.split('|')[1].strip() book_info['isbn'] = info.split('|')[2].strip() book_info['publish_date'] = info.split('|')[3].strip() book_info['vip_price'] = result.xpath("./li[@class='result_book']/ul/li[@class='book_dis']/text()")[0] book_info['price'] = result.xpath("./li[@class='result_book']/ul/li[@class='book_price']/text()")[0] # print(f'解析出的圖書信息為:{book_info}') books.append(book_info) except Exception as e: print("解析數(shù)據(jù)出現(xiàn)異常,忽略!") return books上面的函數(shù)主要解析的是一頁圖書列表數(shù)據(jù),同樣基于 xpath 定位相應(yīng)的元素,然后提取我們想要的數(shù)據(jù)。其中由于部分信息合在一起,我們?cè)谔崛?shù)據(jù)后還要做相關(guān)的處理,分別提取對(duì)應(yīng)的信息。我們可以從網(wǎng)頁中直接樣 HTML 拷貝下來,然后對(duì)該函數(shù)進(jìn)行測(cè)試:提取圖書列表的網(wǎng)頁數(shù)據(jù)我們把保存的網(wǎng)頁命名為 test.html,放到與該代碼同級(jí)的目錄下,然后進(jìn)入命令行操作:>>> from china_pub_crawler import parse_books_page>>> f = open('test.html', 'r+')>>> html_content = f.read()>>> parse_books_page(html_content)[{'title': '(特價(jià)書)零基礎(chǔ)學(xué)ASP.NET 3.5', 'book_url': 'http://product.china-pub.com/216269', 'author': '王向軍;王欣惠 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111261414', 'publish_date': '2009-02-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥58.00'}, {'title': 'Objective-C 2.0 Mac和iOS開發(fā)實(shí)踐指南(原書第2版)', 'book_url': 'http://product.china-pub.com/3770704', 'author': '(美)Robert Clair (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111484561', 'publish_date': '2015-01-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥79.00'}, {'title': '(特價(jià)書)ASP.NET 3.5實(shí)例精通', 'book_url': 'http://product.china-pub.com/216272', 'author': '王院峰 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111259794', 'publish_date': '2009-01-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥55.00'}, {'title': '(特價(jià)書)CSS+HTML語法與范例詳解詞典', 'book_url': 'http://product.china-pub.com/216275', 'author': '符旭凌 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111263647', 'publish_date': '2009-02-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥39.00'}, {'title': '(特價(jià)書)Java ME 游戲編程(原書第2版)', 'book_url': 'http://product.china-pub.com/216296', 'author': '(美)Martin J. Wells; John P. Flynt (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111264941', 'publish_date': '2009-03-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥49.00'}, {'title': '(特價(jià)書)Visual Basic實(shí)例精通', 'book_url': 'http://product.china-pub.com/216304', 'author': '柴相花 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111263296', 'publish_date': '2009-04-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥59.80'}, {'title': '高性能電子商務(wù)平臺(tái)構(gòu)建:架構(gòu)、設(shè)計(jì)與開發(fā)[按需印刷]', 'book_url': 'http://product.china-pub.com/3770743', 'author': 'ShopNC產(chǎn)品部 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111485643', 'publish_date': '2015-01-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥79.00'}, {'title': '[套裝書]Java核心技術(shù) 卷Ⅰ 基礎(chǔ)知識(shí)(原書第10版)+Java核心技術(shù) 卷Ⅱ高級(jí)特性(原書第10版)', 'book_url': 'http://product.china-pub.com/7008447', 'author': '(美)凱S.霍斯特曼(Cay S. Horstmann)????(美)凱S. 霍斯特曼(Cay S. Horstmann) (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787007008447', 'publish_date': '2017-08-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥258.00'}, {'title': '(特價(jià)書)Dojo構(gòu)建Ajax應(yīng)用程序', 'book_url': 'http://product.china-pub.com/216315', 'author': '(美)James E.Harmon (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111266648', 'publish_date': '2009-05-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥45.00'}, {'title': '(特價(jià)書)編譯原理第2版.本科教學(xué)版', 'book_url': 'http://product.china-pub.com/216336', 'author': '(美)Alfred V. Aho;Monica S. Lam;Ravi Sethi;Jeffrey D. Ullman (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111269298', 'publish_date': '2009-05-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥55.00'}, {'title': '(特價(jià)書)用Alice學(xué)編程(原書第2版)', 'book_url': 'http://product.china-pub.com/216354', 'author': '(美)Wanda P.Dann;Stephen Cooper;Randy Pausch (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111274629', 'publish_date': '2009-07-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥39.00'}, {'title': 'Java語言程序設(shè)計(jì)(第2版)', 'book_url': 'http://product.china-pub.com/50051', 'author': '趙國(guó)玲;王宏;柴大鵬 (著)', 'publisher': '機(jī)械工業(yè)出版社*', 'isbn': '9787111297376', 'publish_date': '2010-03-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥32.00'}, {'title': '從零開始學(xué)Python程序設(shè)計(jì)', 'book_url': 'http://product.china-pub.com/7017939', 'author': '吳惠茹 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111583813', 'publish_date': '2018-01-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥79.00'}, {'title': '(特價(jià)書)匯編語言', 'book_url': 'http://product.china-pub.com/216385', 'author': '鄭曉薇 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111269076', 'publish_date': '2009-09-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥29.00'}, {'title': '(特價(jià)書)Visual Basic.NET案例教程', 'book_url': 'http://product.china-pub.com/216388', 'author': '馬玉春;劉杰民;王鑫 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111272571', 'publish_date': '2009-09-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥30.00'}, {'title': '小程序從0到1:微信全棧工程師一本通', 'book_url': 'http://product.china-pub.com/7017943', 'author': '石橋碼農(nóng) (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111584049', 'publish_date': '2018-01-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥59.00'}, {'title': '深入分布式緩存:從原理到實(shí)踐', 'book_url': 'http://product.china-pub.com/7017945', 'author': '于君澤 (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111585190', 'publish_date': '2018-01-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥99.00'}, {'title': '(特價(jià)書)ASP.NET AJAX服務(wù)器控件高級(jí)編程(.NET 3.5版)', 'book_url': 'http://product.china-pub.com/216397', 'author': '(美)Adam Calderon;Joel Rumerman (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111270966', 'publish_date': '2009-09-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥65.00'}, {'title': 'PaaS程序設(shè)計(jì)', 'book_url': 'http://product.china-pub.com/3770830', 'author': '(美)Lucas Carlson (著)', 'publisher': '機(jī)械工業(yè)出版社', 'isbn': '9787111482451', 'publish_date': '2015-01-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥39.00'}, {'title': 'Visual C++數(shù)字圖像處理[按需印刷]', 'book_url': 'http://product.china-pub.com/2437', 'author': '何斌 馬天予 王運(yùn)堅(jiān) 朱紅蓮 (著)', 'publisher': '人民郵電出版社', 'isbn': '711509263X', 'publish_date': '2001-04-01出版', 'vip_price': 'VIP會(huì)員價(jià):', 'price': '¥72.00'}]是不是能正確提取圖書列表的相關(guān)信息?這也說明我們的函數(shù)的正確性,由于也可能在解析中存在一些異常,比如某個(gè)字段的缺失,我們需要捕獲異常并忽略該條數(shù)據(jù),讓程序能繼續(xù)走下去而不是停止運(yùn)行。在完成了上述的工作后,我們來通過對(duì)頁號(hào)的 URL 構(gòu)造,實(shí)現(xiàn)采集多個(gè)分頁下的數(shù)據(jù),最后達(dá)到讀取完該分類下的所有圖書信息的目的。完整代碼如下:def get_category_books(category, url): """ 獲取類別圖書,下面會(huì)有分頁,我們一直請(qǐng)求,直到分頁請(qǐng)求返回404即可停止 :return: """ books = [] page = 1 regex = "(http://.*/)([0-9]+)_(.*).html" pattern = re.compile(regex) m = pattern.match(url) if not m: return [] prefix_path = m.group(1) current_page = m.group(2) if current_page != 1: print("提取數(shù)據(jù)不是從第一行開始,可能存在問題") suffix_path = m.group(3) current_page = page while True: # 構(gòu)造分頁請(qǐng)求的URL book_url = f"{prefix_path}{current_page}_{suffix_path}.html" response = requests.get(url=book_url, headers=headers) print(f"提取分類[{category}]下的第{current_page}頁圖書數(shù)據(jù)") if response.status_code != 200: print(f"[{category}]該分類下的圖書數(shù)據(jù)提取完畢!") break response.encoding = 'gbk' # 將該分頁的數(shù)據(jù)加到列表中 books.extend(parse_books_page(response.text)) current_page += 1 # 一定要緩一緩,避免對(duì)對(duì)方服務(wù)造成太大壓力 time.sleep(0.5) return books最后保存數(shù)據(jù)到 MongoDB 中,這一步非常簡(jiǎn)單,我們前面已經(jīng)操作過 MongoDB 的文檔插入,直接搬用即可:client = pymongo.MongoClient(host='MongoDB的服務(wù)地址', port=27017)client.admin.authenticate("admin", "shencong1992")db = client.scrapy_manualcollection = db.china_pub# ...def save_to_mongodb(data): try: collection.insert_many(data) except Exception as e: print("批量插入數(shù)據(jù)異常:{}".format(str(e)))正是由于我們前面生成了批量的 json 數(shù)據(jù),這里直接使用集合的 insert_many() 方法即可對(duì)采集到的數(shù)據(jù)批量插入 MongoDB 中。代碼的最后我們加上一個(gè) main 函數(shù)即可:# ...if __name__ == '__main__': page_url = "http://www.china-pub.com/Browse/" categories, urls = get_all_computer_book_urls(page_url) # print(categories) books_total = {} for i in range(len(urls)): books_category_data = get_category_books(categories[i], urls[i]) print(f"保存[{categories[i]}]圖書數(shù)據(jù)到mongodb中") save_to_mongodb(books_category_data) print("爬取互動(dòng)出版網(wǎng)的計(jì)算機(jī)分類數(shù)據(jù)完成")這樣一個(gè)簡(jiǎn)單的爬蟲就完成了,還等什么,開始跑起來吧!!

直播
查看課程詳情
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)