功能描述: @PathVariable 注解用來獲取 URL 中變量的值。什么是 URL 中的變量?還是用一個實例來說話:@RequestMapping("/user/{userId}")public String getUserById(@PathVariable("userId") String userId){}{userId} 就是變量占位符。具體請求時,可使用一個真實值替換。如請求格式:http://localhost:8888/user/1 時,@PathVariable 可以為 getUserById() 方法中的 userId 參數注入值 1。@PathVariable 注解同樣有一個 required 屬性,表示是否強制 URL 中有變量的存在。boolean required() default true;@PathVariable 注解非常有用,請你一定要記住它。
Django 中傳遞參數給視圖函數的方式主要可分為以下兩種形式:URL 傳參和非 URL 傳參兩種。第一種基于 Django 中的 URLconf 配置,可以通過 URL 路徑將對應匹配的參數傳到視圖函數中;而另外一種就是屬于HTTP 請求攜帶的參數了,請求參數可以放到 URL 中以 ? 格式加到 URL 的最后面,也可以將參數放到請求 body 中,最后統一由視圖函數中的 request 參數保存并傳到視圖函數中。
在nginx.conf的中加入如下配置:...stream { server { listen 3000; return '3000 server get ip: $remote_addr!\n'; } server { listen 30; # 注意,只寫ip和port,不要加上[http:]之類的,這里是四層的協議 proxy_pass 127.0.0.1:3000; }}...啟動 nginx 后,我們在外面通過 telnet 命令訪問該主機的 3000 和 30端口,可以看到如下結果:[shen@shen ~]$ telnet 180.76.152.113 3000Trying 180.76.152.113...Connected to 180.76.152.113.Escape character is '^]'.3000 server get ip: 103.46.244.108![shen@shen ~]$ telnet 180.76.152.113 30Trying 180.76.152.113...Connected to 180.76.152.113.Escape character is '^]'.3000 server get ip: 127.0.0.1!Connection closed by foreign host.可以看到,訪問30端口時,nginx 幫我們轉發 tcp 層流量到 3000端口,最后返回了相關響應字符串。
<EditText xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/input_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="請輸入密碼" android:imeOptions="actionDone" android:inputType="textPassword" android:maxLines="5" android:textSize="20sp" />代碼比較簡單,主要實現了以下幾個屬性:android:hint="請輸入密碼"用來提示用戶,本輸入框的功能是輸入密碼,當你點擊EditText往里面輸入字符之后,提示就會消失。android:inputType="textPassword"設置當前輸入的類為密碼,那么當用戶輸入文本后,系統會用“*”或者“·”替代。android:maxLines="3"設置當前的輸入框最多使能容納3行內人,如果多余 3 行,則會采用滾動條的形式上下滑動。效果如下:
3.2.1 生成 SSL 證書這里的證書包含服務端證書和客戶端證書。服務端證書用于配置 Tomcat,使瀏覽器驗證服務器的真實性??蛻舳俗C書需要安裝到用戶瀏覽器中,用來開啟 SSL 客戶端認證。服務端配置方式如下:<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="${catalina.home}/conf/server.jks" keystoreType="JKS" keystorePass="password" truststoreFile="${catalina.home}/conf/server.jks" truststoreType="JKS" truststorePass="password"/>即使客戶端瀏覽器不提供證書,clientAuth 也同樣可以置為 true,此時客戶端如果不提供 X.509 認證平局,則其不會被授權訪問 Spring Security 資源。
有時候我們希望接口允許有任意的屬性,語法是用 [] 將屬性包裹起來:// 語法interface Clothes { color?: string; size: string; readonly price: number; [propName: string]: any;}// 任意屬性 activitylet myClothes: Clothes = { size: 'XL', price: 98, activity: 'coupon'}代碼解釋: 這里的接口 Clothes 可以有任意數量的屬性,并且只要它們不是 color size 和 price,那么就無所謂它們的類型是什么。項目案例:使用 axios 庫發起 HTTP 傳輸的時候,可以寫入一個自定義的屬性,就是因為源碼中定義了一個任意屬性:this.$axios({ method: 'put', url: '/cms/user', data: { nickname: this.nickname, }, showBackend: true,})
此時我們可以根據 JSP 模板引擎,按模板規則顯示商品信息了。實例:<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>商品列表</title></head><body> <div>商品列表:</div> <c:forEach var="item" items="${goodsList}"> ${item.name}--${item.price}--${item.pic} </c:forEach></body></html>注意我們通過 JSP 的模板語法,輸出了商品列表信息。關于 JSP 模板引擎更多的語法規則,感興趣的同學可以后續查閱更多資料。
Protocols 描述了如何以異步的方式處理網絡中的事件。HTTP、DNS 以及 IMAP 是應用層協議中的例子。Protocols實現了 IProtocol 接口,它包含如下的方法:makeConnection(): 在 transport 對象和服務器之間建立一個連接;connectionMade(): 連接建立起來后調用;dataReceived(): 接收數據時調用;connectionLost(): 關閉連接時調用;Factory 和 Protocol 有嚴格的不同。Factory 的工作是管理連接事件,并且創建 Protocol 對象處理每一個成功的連接。一旦連接建立,Protocol 對象就接管下面的工作了,包括收發數據和決定是否關閉連接。
Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行時。Node.js 并不是運行在瀏覽器里的一個庫或框架。Node.js 可以提供了一系列服務端能力,如 HTTP 服務、讀寫本地文件等,開發者可以利用 JavaScript 來使用這些能力,因為前端開發者的主要語言就是 JavaScript,所以利用 Node.js 可以降低學習成本,讓前端開發者更容易接觸到服務端開發。
以上是設置 View 與父布局的相對位置,當 RelativeLayout 中有了 View 之后,我們同樣可以設置 View 與其他兄弟 View 的位置關系。android:layout_above="@id/center":這個屬性設置當前 View 擺放在 id 為 center 的 View 的上方。android:layout_below="@id/center":設置當前View擺放在 id 為 center 的 View 的下方。android:layout_toLeftOf="@id/center":設置當前 View 擺放在 id 為 center 的 View 的左邊。android:layout_toRightOf="@id/center":設置當前 View 擺放在 id 為 center 的 View 的右邊。注:可以看到這個屬性是需要指定一個 id 的,所以我們需要給被依賴的兄弟 View 賦予一個 id。但是要注意的是與賦予 id 時用“+id”不同,在指定兄弟 View 的時候,不需要寫“+id”,即直接寫 id 即可。參考代碼如下:<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="#FFdddddd" android:text="centerInParent" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/center" android:layout_centerInParent="true" android:background="#F30C5D" android:text="above" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/center" android:layout_centerInParent="true" android:background="#ECEC18" android:text="below" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_toLeftOf="@id/center" android:background="#14CEE6" android:text="left" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_toRightOf="@id/center" android:background="#25EC0F" android:text="right" android:textSize="20sp" /></RelativeLayout>
URL 的中文名稱為統一資源定位符。簡單來說,它就是一個地址,是我們請求互聯網上某一個資源地址或者某一個服務接口的完整路徑。我們找一個網站的實際 URL 例子,來說明下完整 URL 的組成部分:URL 示例這個慕課網上的完整的 URL 地址為: https://coding.imooc.com/class/evaluation/393.html?page=5#Log。URL 的格式如下:schema://host[:port]/path…/[?query-string]#fragmentschema:表示協議,常見的有 http/https 協議,還有 ftp 協議,ws/wss 協議(websocket)等等;host:域名或者直接是 IP 地址。本例子使用的是慕課網的一個子域名:coding.imooc.com;port:不寫會使用默認端口,非默認地址一定要寫明端口號。本例中使用默認端口 443;path:資源地址,會有多個 / 表示路徑層級。本例中的路徑為 /class/evaluation/393.html;query-string:如果 URL 帶參數,放到 ? 之后, # 號之前,使用 key=value 形式,多個參數之間使用 & 進行連接。本例中的參數是 ?page=5;錨點:或稱片段(fragment),HTTP 請求不包括錨部分,從 # 開始到最后,都是錨部分。本例中的錨部分是 Log。錨部分不是一個 URL 必須的部分。
除了 Django 定義的簡單類型,我們還可以自定義參數類型轉換器來支持更為復雜的 URL 場景。比如前面的 int 類型并不支持負整數,我希望開發一個能匹配正負數的類型,具體的步驟如下:在 hello_app/urls.py 中定義一個 SignInt 類。該類有一個固定屬性 regex,用于匹配動態值;兩個固定方法:to_python() 方法和 to_url() 方法:# hello_app/urls.pyclass SignInt: regex = '-*[0-9]+' def to_python(self, value): # 將匹配的value轉換成我們想要的類型 return int(value) def to_url(self, value): # 反向生成url時候回用到 return value注冊該定義的轉換器,并給出一個簡短的名字,比如 sint:# hello_app/urls.pyfrom django.urls import converters, register_converterregister_converter(SignInt, 'sint')...最后,我們就可以在 URLconf 中使用該類型來配置動態的 URL 表達式:# hello_app/urls.pyurlpatterns = [ path('articles/<sint:signed_num>/', views.signed_convert),]# hello_app/views.pydef signed_convert(request, signed_num, **kwargs): return HttpResponse('hello, 自定義類型轉換器,獲取參數={}\n'.format(signed_num))啟動 Django 服務后,執行相關請求,可以看到 Django 的路由系統能成功匹配到帶負數和正數的 URL:[root@server ~]# curl http://127.0.0.1:8881/hello/articles/1998/hello, 自定義類型轉換器,獲取參數=1998[root@server ~]# curl http://127.0.0.1:8881/hello/articles/-1998/hello, 自定義類型轉換器,獲取參數=-1998
接下來的幾個屬性能夠將 View 固定在相對于父布局任意一條邊固定距離的位置。android:layout_alignParentTop=“true”:使用layout_alignParentTop屬性可以讓你的View與父布局的頂端對齊,同時由于RelativeLayout的長寬是match_parent,所以最終的效果就是顯示在屏幕的最上方。android:layout_alignParentBottom=“true”:使用layout_alignParentBottom屬性可以讓你的View與父布局的底部對齊,最終的效果就是顯示在屏幕的最下方。android:layout_alignParentLeft=“true”:使用layout_alignParentBottom屬性可以讓你的View與父布局的左側對齊,最終的效果就是顯示在屏幕的最左側。android:layout_alignParentRight=“true”:使用layout_alignParentRight屬性可以讓你的View與父布局的右側對齊,最終的效果就是顯示在屏幕的最右側。注:以上幾個對齊屬性都可以多個搭配使用,比如我們上圖中的幾個View,分別是右上對齊、左下對齊和右中對齊參考代碼如下:<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:background="#F75549" android:text="right|top" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentBottom="true" android:layout_centerVertical="true" android:background="#F1E14D" android:text="left|bottom" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerInParent="true" android:layout_centerVertical="true" android:background="#14CEE6" android:text="right|centerInParent" android:textSize="20sp" /></RelativeLayout>
了解 TCP: TCP 協議適用于客戶端數量相對比較少,并且通信頻繁的業務場景;Http 協議則適用于客戶端數量比較大的業務場景。因為 Http 是短連接,請求完成即會釋放連接資源,不再占用服務器資源,但是,TCP 則不會,連接成功,則可以多次請求,不會釋放,除非特殊原因導致連接斷開。面臨問題: 既然長連接是不會釋放連接資源,那么如果很多客戶端只是完成了連接,但是并沒有實際的業務請求操作,那么服務器的資源還是被占用,導致服務器性能下降。解決辦法: 把那些長期占用連接資源,但是并沒有實際業務操作的連接斷開掉,等它們需要做業務操作的時候,再重連服務器。這樣可以達到即使釋放沒用的資源,提高服務器的性能。總結,心跳機制主要有以下兩個方面的作用定時剔除哪些沒用的連接,減輕服務端的壓力;適用于中間件(比如:RPC 框架),服務端規定時間內沒用收到客戶端的心跳數據,則可以認為其宕機,服務端剔除對于的映射關系。
通常,在生產環境中使用 Nginx 進行反向代理和負載均衡或者各種其他處理時,良好的日志記錄是非常關鍵的一環。通過精心配置的 Nginx 日志,我們可以獲取用戶的真實 ip、瀏覽器信息,請求處理時間,請求URL等,這樣方便我們排查和回溯錯誤。具體要記錄哪些信息,可以通過 Nginx 中的 log_format 指令定義,由它定義日志的格式。而對于使用哪種日志格式和設置日志的保存路徑則由 access_log 指令指定的。另外在 Nginx 中還有一個配置服務器和請求處理過程中的錯誤信息的指令,那就是 error_log指令。最后,如果在配置的日志文件路徑中使用了變量,我們可以通過open_log_file_cache指令來設置緩存,提升性能。對于大型的網站而言,大量的 http 請求意味著大量的日志記錄,及時按天或按大小進行 Nginx 日志備份也至關重要的。在 Nginx 的日志模塊主要有2個, ngx_stream_log_module 和 ngx_http_log_module,分別表示四層的日志模塊和七層的日志模塊,其指令和用法都是一致的,接下來我們只針對 http 請求的日志進行說明和使用。
目前官方最新版本(截止到 2019 年 12 月 12 日)為 1.17.6,我們直接去官網找到下載地址。不推薦直接使用 yum 安裝,因為存在如下兩個問題:版本太舊,以 CentOS 為例,直接 yum 安裝的版本是 1.12.2 版本,已經嚴重脫離了時代;無法自定義安裝模塊,安裝目錄等等,不方便后續的實驗。# 下載nginx安裝包$ wget http://nginx.org/download/nginx-1.17.6.tar.gz # 解壓安裝包$ tar -xzf nginx-1.17.6.tar.gz
我們在項目的根目錄下創建 server.js,用來啟動 vue 項目:const fs = require("fs");const path = require("path");const bodyParser = require("body-parser");const express = require("express");const app = express();const list = require("./mock/list.json");app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: false })); // 服務開啟后訪問指定編譯好的dist文件下的數據app.use(express.static(path.resolve(__dirname, "./dist")));app.get("/todo/list", (req, res) => { res.json({ data: list });});app.get("*", function(req, res) { const html = fs.readFileSync( path.resolve(__dirname, "./dist/index.html"), "utf-8" ); res.send(html);});app.listen(8081);運行命令:node start.js然后,訪問 http://localhost:8081/#/ 就可以正常預覽項目了。
由于不限制選中數量,Checkbox 控件不存在類似 RadioGroup 的父容器,我們可以直接在布局文件中寫<Checkbox/>標簽,如下:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/group" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:orientation="horizontal"> <CheckBox android:id="@+id/cb_android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="Android" /> <CheckBox android:id="@+id/cb_ios" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="iOS" /></LinearLayout>我們看到可以有兩個選項同時被選中,和 RadioButton 一樣,通過android:checked屬性設置默認選中的選項。
PREACCESS、ACCESS 和 POST_ACCESS 是和 Http 請求訪問權限相關的階段。PREACCESS 階段是在連接之前要做的訪問控制, 這個階段有 limit_conn 和 limit_req 等模塊工作。ACCESS 階段是解決用戶能不能訪問,比如根據用戶名、密碼限制用戶訪問(auth_basic 模塊)、根據 ip 限制用戶訪問(access 模塊)以及第三方模塊認證限制用戶的訪問(auth_request模塊)。POST_ACCESS 是在 ACCESS 之后要做的一些工作。
在 CSS 中我們可以通過 @import 來導入一個樣式文件,Sass 擴展了 CSS 的 @import 規則,使得可以導入 CSS 后綴的樣式文件和 Scss 后綴的樣式文件,并且提供了對 mixin 、函數和變量的訪問。與 CSS 的 @import 不同的是, CSS 使用 @import 導入文件是在頁面渲染的時候發起多個 http 請求來獲取文件內容,而 Sass 的導入 @import 是在編譯時獲取文件內容導入的。
比較早之前,部署 Java web 服務只是單純使用 Tomcat 做 Web 服務器,前后端代碼融合在一個工程之中。Tomcat 啟動后對外提供一個端口接收和相應 http請求。隨著 Nginx 的越來越流行,同時加上其優秀的反響代理和負載均衡功能,我們在線上的 Java web 通常會結合二者,即使用 Nginx + Tomcat 的方式來部署 Java web 服務。最近兩年,隨著微服務化和前后端工程分離思想的流行,使用 Spring Boot 和 Vue 框架進行 Java web 開發的人的人越來越多。由于前后端分離后需要解決請求跨域的問題,往往會使用 Nginx 做一層反向代理,這樣可以減少一些代碼風險。所以,目前主流的 Java web開發模式是:基于 Vue 等優秀的前端框架完成頁面開發;使用 Spring Boot 等 java web 框完成后端服務開發;前端工程打包后是一堆靜態文件,可以直接由 Nginx 進行代理訪問;后端服務啟動后會占用端口等待請求,Nginx 將使用反向代理功能將前端發起的 http 請求轉到對應的后臺服務去處理。如果在多臺機器上部署了相同的服務,還可以使用 Nginx 中的負載均衡功能,將請求均勻分發到上游的服務,實現系統的高可用性。
同樣,在 Scrapy 中為我們內置了不少的下載中間件,可以方便地配置下載參數,比如 Cookie、代理等。我們現在來介紹一些常用的下載中間件。CookiesMiddleware:該中間件主要用于給請求加上 Cookie,這樣可以方便我們的爬蟲程序使用 Cookie 去訪問網站。它記錄了向 Web Server 發送的 Cookie,并在之后的 Request 請求中帶上該 Cokkile,就像我們操作瀏覽器那樣。該中間件在 settings.py 中的配置有2個:COOKIES_ENABLE:默認為 True,表明啟用 cookies 中間件,如果為 False,則不會使用 cookies。Tips:如果 Request.meta 參數的 dont_merge_cookies 的值為 True,那么無論 COOKIES_ENABLE 指定為何值,cookies 在這個請求的來回中都不會做任何處理;COOKIES_DEBUG:默認為 False。如果為 True,則會記錄所有請求發送的 cookies 和響應接收到的 cookies;HttpProxyMiddleware:該中間件通過在 Request.meta 中添加 proxy 屬性值為該請求設置 HTTP 代理;HttpCacheMiddleware:該中間件為所有 HTTP 請求和響應提供 low-level 緩存,它需要和緩存存儲后端以及緩存的策略相結合;DefaultHeadersMiddleware:該中間件通過配置文件中 DEFAULT_REQUEST_HEADERS 的值來設置所有請求默認的請求頭;DownloadTimeoutMiddleware:該中間件主要用來設置下載超時時間。對應 settings.py 中的配置值為:DOWNLOAD_TIMEOUT或者 spider 的 download_timeout 屬性好了,常用的下載中間件就介紹這么多了,其余的可以繼續參考官方文檔,寫的非常詳細。
geo 坐標系需要自行提供地理信息數據,使用上有一定的不便,因此 echarts 提供了另一種地理坐標系實現 —— bmap。bmap 擴展將百度地圖帶入 echarts,以百度地圖為底圖繪制地理坐標系,所以使用上就不用再關注地理數據了,而且依托于百度地圖提供的強大功能,bmap 在伸縮、移動、精度等方面更出色。使用時,除了 echarts 文件外,還需要引入百度地圖依賴、bmap 擴展依賴,以 CDN 為例:<!-- 引入百度地圖的jssdk --><!-- 配置方法可參考: http://lbsyun.baidu.com/index.php?title=jspopular3.0 --><script src="http://api.map.baidu.com/api?v=2.0&ak="></script><!-- 引入 ECharts --><script src="http://cdn.bootcss.com/echarts/4.5.0/echarts.js"></script><!-- 引入 bmap 擴展 --><script src="http://cdn.bootcss.com/echarts/4.5.0/extension/bmap.min.js"></script>引入后,就可以通過 bmap 配置地理坐標系。bmap 所支持的配置項比較少,包括:配置名類型默認值說明centerarray當前視圖的中心點,用經緯度表示roamboolean|stringfalse是否開啟鼠標縮放和平移漫游。zoomnumber1當前視角的初始化縮放比例mapStyleobject舊版地圖的自定義樣式接口,詳見: http://developer.baidu.com/map/jsdevelop-11.htmmapStyleV2object新版地圖的自定義樣式,詳見: http://developer.baidu.com/map/jsdevelop-11.htmbmap 包含了百度地圖所支持的所有地理區域信息,所以應用時只需通過 center 指定視圖中心點,通過 zoom 控制視圖區域,即可實現地理坐標系,示例:1321示例效果:此外,還可以通過 myChart.getModel().getComponent('bmap').getBMap(); 接口獲取 bmap 對應的地圖實例,實現與地圖的交互。在上述示例基礎上,添加額外代碼:// 獲取地圖實例var map = myChart.getModel().getComponent('bmap').getBMap();// 添加交通狀況層var traffic = new BMap.TrafficLayer();map.addTileLayer(traffic);// 重置視圖中心map.centerAndZoom(new BMap.Point(114.48, 38.03), 8);示例效果;完整的開發指南,請參考 百度地圖。
如果是轉發,數據模型只需要是請求作用域級別的,視圖解析器便能從數據模型中拿到所需要的數據。對于重定向,因為跨了請求,視圖無法讀出請求作用域級別的數據模型中的數據。如果要讓數據模型中的數據被視圖識別出來,則需要提升數據模型的作用域,如升級為會話作用域級別。所謂會話作用域,意味著數據會存放在服務器的會話緩存區。如果數據使用的頻率不是很高,會產生空間上的浪費。有沒有一種較佳的方案,即不浪費服務器空間,又能傳遞數據了?答案是肯定的。最原始的方式便是采用查詢字符串的方式。如下面的實例:@RequestMapping("/response03") public String response03(ModelMap model) throws IOException { // 發送給客戶端的響應數據 String hello = "Hello"; model.addAttribute("data", hello); return "redirect:/hello.jsp"; }model 中的數據只是請求作用域級別,重定向后的 hello.jsp 中無法獲取此數據, Spring MVC 內部處理方式是把數據附加在 hello.jsp 后面。打開瀏覽器,輸入請求 http://localhost:8888/sm-demo/response03 地址,查看瀏覽器的地址欄中的 URL 變成 http://localhost:8888/sm-demo/hello.jsp?data=Hello。Tips:數據附加在 URL 后面是 Spring MVC 自動完成的。把 hello.jsp 頁面中的數據讀取方式改成下面的方式(從查詢參數中讀?。?。<div style="color:red">${param.data} </div> 這種方式有 2 個缺點:安全性低,數據赤裸裸地暴露在地址欄中;如果數據量多,則整個 URL 變得臃腫不易維護。多數據實例:@RequestMapping("/response03") public String response03(ModelMap model) throws IOException { // 發送給客戶端的響應數據 String hello = "Hello"; model.addAttribute("data", hello); model.addAttribute("id", 1); return "redirect:/hello.jsp"; }當請求后,URL 會變成 http://localhost:8888/sm-demo/hello.jsp?data=Hello&id=1 。
XMLHttpRequest 實質上就是一種具有發送異步請求功能的技術,是一個可以在 javaScript 、JScript 、VBScript 等腳本語言中使用的 API 對象。它可以通過異步發送 HTTP 請求,完成前后端的交互。在我們的客戶端界面上,無刷新交互只是一種表現,而異步發送請求才是這個技術的根本。目前為止,XMLHttpRequest 早已成為正式的規范。并且在大多數瀏覽器上都得到了支持。
將 select 查詢寫在 mapper.xml 文件中,比如:<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.imooc.mybatis.mapper.UserMapper"> <select id="selectUserAgeById" parameterType="java.lang.Integer" resultType="java.lang.Integer"> SELECT age FROM imooc_user WHERE id = #{id} </select></mapper>其中名為 selectUserAgeById 的 select 標簽(一般以 id 做為名稱),接收 Integer 類型的參數(parameterType),并返回 Integer 類型的結果(resultType);再看 select 標簽中的查詢語句,接收 id 參數,類型為 int,返回 age,類型為 int,二者一一對應。
響應頭部信息HTTP/1.1 200 OKDate:Sun, 23 Feb 2020 07:31:24 GMTConnection: keep-aliveContent-Encoding: gzipContent-Length: 129Content-Type: application/json; charset=UTF-8...返回了請求的狀態,200狀態碼對應的就是成功,還有一些鏈接狀態,內容的編碼,長度,媒體類型等。響應的正文{result: 0, data: ["Vue", "Python", "Java", "flutter", "springboot", "docker", "React", "小程序"],…}data: ["Vue", "Python", "Java", "flutter", "springboot", "docker", "React", "小程序"]msg: "成功"result: 0返回了消息的具體信息,這個消息有可能是一串 html 文本,也可能是 json 串,圖片,附件都有可能,一般是跟 content-type 對應。
通常對于 Python 第三方模塊的學習方式都是一樣的。第一步都是先安裝,然后是不斷的使用和參考官方文檔,待熟練掌握后便可以翻看其源碼深入學習其實現原理,最后達到徹底掌握該模塊的地步。[store@server2 chap02]$ pip3 install requests -i http://pypi.douban.com/simple/接下來我們參考官方文檔的第一個實例進行測試,該實例主要是測試 requests 庫的一些方法及其使用場景,后面我們會使用 requests 庫對網頁的數據進行手工爬取以比較和框架爬蟲之間的區別。后續都將會在 CentOS7.8 和 Python 3 的環境下:[store@server2 chap02]$ 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.>>> import requests>>>Scrapy 百度百科接下來我們使用 requests 模塊的 get() 方法模擬 http 的 get 請求,獲取這樣的頁面結果:>>> headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'}>>> r1 = requests.get(url='https://baike.baidu.com/item/scrapy', headers=headers)>>> r1.status_code200>>> r1.text[:1000]'<!DOCTYPE html>\n<!--STATUS OK-->\n<html>\n\n\n\n<head>\n<meta charset="UTF-8">\n<meta http-equiv="X-UA-Compatible" content="IE=Edge" />\n<meta name="referrer" content="always" />\n<meta name="description" content="Scrapy是適用于Python的一個快速、高層次的屏幕抓取和web抓取框架,用于抓取web站點并從頁面中提取結構化的數據。Scrapy用途廣泛,可以用于數據挖掘、監測和自動化測試。Scrapy吸引人的地方在于它是一個框架,任何人都可以根據需求方便的修改。它也提供了多種類型爬蟲的基類,如BaseSpider、sitemap爬蟲等,最新版本又提供了web2.0爬蟲的支持。...">\n<title>scrapy_百度百科</title>\n<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />\n<link rel="icon" sizes="any" mask >\n\n<meta name="keywords" content="scrapy scrapy基本功能 scrapyScrapy架構 scrapy如何開始">\n<meta name="image" content="https://bkssl.bdimg.com/cms/static/baike.png">\n<meta name="csrf-token" content="">\n<meta itemprop="dateUpdate" content="2020-03-19 08:23:19" />\n\n<!--[if lte IE 9]>\n<script>\r\n (function() {\r\n var e = "abbr,article,aside,audio,canvas,datalist,details,dialog,eventsource,figure,footer,header,hgroup,mark,menu,meter,nav,outpu注意:這里 headers 非常重要,很多網站第一步會檢查 headers,如果請求頭中沒有 User-Agent 就會直接判定為爬蟲并采取相應措施進行限制。如下是沒有加上 headers 的請求結果:沒有 headers 的結果看到了么,簡簡單單的 get() 方法就能模擬 HTTP 的 get 請求,那么是不是還有 post()、put()、delete() 這些方法呢?答案是肯定的。
路由是用來定義 RESTful Web API 不同接口所對應的不同路徑地址。在本案例中,我們是要獲得學生的信息,根據第 3 節中介紹的設計規范,地址應設計為:http://www.demo.com/api/students 。在 ProjectDemo 的 urls.py 中定義路由信息。from django.contrib import adminfrom django.urls import path, includefrom rest_framework import routersfrom AppDemo.views import StudentsViewSetrouter = routers.DefaultRouter() # 創建路由器router.register(r'students', StudentsViewSet) # 在路由器中注冊視圖集路由地址urlpatterns = [ # 拼接路由路徑 path('api/', include(router.urls)),]
業務碼不屬于 Http 協議的成員,是實踐中的產物。它是定義在返回的消息實體中的,并沒有固定的格式,但無非就是下面3種模塊?!惧e誤級別(可選)】-【功能模塊(必要)】-【具體錯誤編號(必要)】錯誤碼一般由 5~6 位整數組成,例子如下:模塊模塊編碼錯誤編碼描述庫存10001庫存不足庫存10002盤盈庫存10002盤虧資金20001參數不正確