Spring Security 默認包含了 Content-Type 頭。如果需要禁用它,可以通過如下方式:@Configuration@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) { http.headers(headers -> headers.contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())); }}
首先修改布局文件,將 ListView 替換成 GridView 并添加一些 GridView 特有的屬性,如下:<?xml version="1.0" encoding="utf-8"?><GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gridview" android:layout_width="match_parent" android:layout_height="match_parent" android:columnWidth="110dp" android:numColumns="auto_fit" android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:stretchMode="columnWidth" android:gravity="center" />
在官方文檔地址中有關于 Nginx 的所有模塊,打開模塊我們就能看到模塊中支持的指令。最常用的指令,如 http、server、listen 等都在 ngx_http_core_modul 模塊中,這個是 Nginx 的核心模塊。
Nginx 部署 Java Web 服務時,主要用到是 Nginx 的代理轉發功能,對于不同類型的接口而言,可能會有不同的轉發邏輯。如果是使用 spring cloud 這樣的微服務框架,每個服務可能會部署多個會這分開部署在不同機器,在 Nginx 同樣只需要使用 proxy_pass 指令將 http 請求轉發到對應的上游服務上即可,同時負載均衡模塊也在 java web 后臺服務中用到的比較多。最后是在java web 的開發中,也常常會涉及到 websocket 協議,因此 Nginx 在部署 java web 服務時也會用到 websocket 代理轉發。所以 Nginx 在部署 Java Web 服務時的基本配置大概如下:...http{ server { # 監聽8080端口 listen 8080; # 指定域名,不指定也可以 server_name www.xxx.com; # 參數調優 client_max_body_size 20m; client_body_buffer_size 128k ... # 如果使用多個后臺服務,可以配置負載均衡 ... # 訪前端的 vue 頁面 location / { ... } # vue 頁面中向后臺 java 服務發送請求 location /xxxx { proxy_pass http://xxxx:xx/xxx; } # 配置多種方向代理,不同類型接口有不同的轉發方式 ... # 如果有,則配置websocket代理 location /xxxy { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_pass http://xxxxx:xx/yyy; } } }...如果涉及的服務較多, Nginx 的配置往往會拆成多個文件進行編寫,這樣就用到了前面提到的 include 指令。
實現重定向功能,它的常用形式如下:from django.shortcuts import redirect# 指定完整的網址def redirect_view1(request): # 忽略其他 return redirect("http://www.baidu.com")# 指定內部path路徑def redirect_view2(request): # 忽略其他 return redirect("/index/")def redirect_view3(request): # 忽略其他 return redirect(reverse('blog:article_list'))def redirect_view4(request): # 忽略其他 return redirect('some-view-name', foo='bar')
本小節主要學習了 URI 的概念,并且區分出了大家容易誤解的 URI 和 URL 的區別。在新版的 Http/2.0 文檔中已經將 URL 修改成了 URI,可能也是怕大家混淆,不過在詳細地了解清楚后,改不改問題都不大了。
Spring MVC 提供有一種所謂的模板方法,和前面的以查詢字符串方法進行附加沒有多大區別。如下面的代碼,數據模型中的 data 對應數據會以 URL 變量方式傳遞。數據模型中其它數據則以查詢字符串方式進行傳遞。@RequestMapping("/response04") public String response04(ModelMap model) throws IOException { // 發送給客戶端的響應數據 String hello = "Hello"; model.addAttribute("data", hello); model.addAttribute("id", 1); return "redirect:/test/{data}"; } ? @RequestMapping("/test/{data}") public String response05(@PathVariable("data") String data,@RequestParam("id") int id) throws IOException { System.out.println(data); System.out.println(id); return null; }當在瀏覽器中請求 http://localhost:8888/sm-demo/response04 后,瀏覽器的地址欄中會變成 :http://localhost:8888/sm-demo/test/Hello?id=1。模板方式其本質和查詢字符串沒有太多區別。
瀏覽器發起請求;Tomcat 響應請求,然后封裝成統一的對象交給 Engine 處理。圖片顯示的是 Http 協議的處理,但是 Tomcat 的設計并不只是為了 Http 這個協議,還可以有其它的如 Ajp 協議。從 Engine 的角度它對這些處理是透明的(可以不關心的);Engine 將請求分配給一臺Host機器去處理;一臺機器上面可能同時部署了多個 Java Web 應用,這時候通過 Context 這個上下文可以定位到具體的哪個 Web 應用;交給應用中具體的某個 Servlet 處理;原路一個個返回,將處理的響應結果傳輸給瀏覽器。
首先在 MyBatis 的全局配置文件中添加如下配置:<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <databaseIdProvider type="DB_VENDOR" /></configuration>在 configuration 中加入 databaseIdProvider 后,還需要在 databaseIdProvider 標簽中添加上需要使用到的數據庫名稱,如:SQL Server。每一個 property 屬性都代表了一個數據庫,name 表示數據庫廠商名稱,value 用來設置別名。<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <databaseIdProvider type="DB_VENDOR"> <property name="SQL Server" value="sqlserver"/> <property name="MySQL" value="mysql"/> <property name="PostgreSQL" value="postgre"/> </databaseIdProvider></configuration>
預先認證的使用場景如:已使用x.509 認證、J2EE 容器等方式通過認證。預認證有兩個主要步驟:識別發起請求的用戶身份;為該用戶返回權限。具體的運行機制與外部認證環境有關。當使用 x.509 證書認證時,用戶的識別信息從證書中獲取并添加在 Http 請求頭中。如果是 J2EE 容器認證,用戶的身份信息通過 Http 請求對象的 getUserPrincipal() 方法獲得。有時,外部認證系統可以提供用戶的身份信息、權限信息,但有時,權限信息要從其他數據源中獲取,例如通過 UserDetailsService。
Spring MVC 內部提供了很多優雅的異常處理機制。其中之一就是把不同的異常映射成 HTTP 狀態碼。如下面實例:首先定義一個異常類:@ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "數字范圍不符合要求?。ú荒苁?20)")public class NumberException extends RuntimeException { }如果在方法中拋出的異常已經被映射成了狀態嗎。則在瀏覽器中顯示出來的異常信息會明確很多。@RequestMapping("/exception")public String test(@RequestParam("num") int num) { if (num == 20) { throw new NumberException(); } return "success";}在瀏覽器中輸入 http://localhost:8888/sm-demo/exception?num=13 。可以看到:定制化的信息已經有所改善,但是,還是不夠友好。
首先需要了解一下 Mixin 的概念,這里有一篇介紹 Python 中 Mixin 的文章:<<多重繼承>> ,可以認真看下,加深對 Mixin 的理解。在我的理解中,Mixin 其實就是單獨的一塊功能類。假設 Django 中提供了 A、B、C 三個視圖類,又有 X、Y、Z三個 Mixin 類。如果我們想要視圖 A,同時需要額外的 X、Y功能,那么使用 Python 中的多重繼承即可達到目的:class NewView(A, X, Y): """ 定義新的視圖 """ pass我們來看看 Django 的官方文檔是如何引出 Mixin 的:Django’s built-in class-based views provide a lot of functionality, but some of it you may want to use separately. For instance, you may want to write a view that renders a template to make the HTTP response, but you can’t use TemplateView;perhaps you need to render a template only on POST, with GET doing something else entirely. While you could use TemplateResponse directly, this will likely result in duplicate code.For this reason, Django also provides a number of mixins that provide more discrete functionality. Template rendering, for instance, is encapsulated in the TemplateResponseMixin.翻譯過來就是: Django 內置的類視圖提供了許多功能,但是我們可能只需要其中的一部分功能。例如我想寫一個視圖,該視圖使用由模板文件渲染后的 HTML 來響應客戶端的 HTTP 請求,但是我們又不能使用 TemplateView 來實現,因為我只想在 POST 請求上使用這個模板渲染的功能,而在 GET 請求時做其他事情。當然,可以直接使用 TemplateResponse 來完成,這樣就會導致代碼重復?;谶@個原因, Django 內部提供了許多離散功能的 mixins??梢钥吹?,這里的 mixins 就是一些單獨功能的類,配合視圖類一起使用,用于組合出各種功能的視圖。接下來,我們結合前面的 Member 表來使用下 mixin 功能。具體的步驟如下:改造原來的視圖類-TestView。我們給原來的視圖類多繼承一個 mixin,用于實現單個對象查找查找功能;from django.shortcuts import renderfrom django.http import HttpResponsefrom django.views.decorators.csrf import csrf_exemptfrom django.views.generic import Viewfrom django.views.generic.detail import SingleObjectMixinfrom .models import Member# Create your views here.class TestView(SingleObjectMixin, View): model = Member def get(self, request, *args, **kwargs): return HttpResponse('hello, get\n') def post(self, request, *args, **kwargs): self.object = self.get_object() return HttpResponse('hello, {}\n'.format(self.object.name)) def put(self, request, *args, **kwargs): return HttpResponse('hello, put\n') def delete(self, request, *args, **kwargs): return HttpResponse('hello, delete\n') @csrf_exempt def dispatch(self, request, *args, **kwargs): return super(TestView, self).dispatch(request, *args, **kwargs)修改 URLConf 配置,傳遞一個動態參數,用于查找表中記錄:urlpatterns = [ path('test-cbv/<int:pk>/', views.TestView.as_view(), name="test-cbv")]啟動服務器,然后進行測試:[root@server first_django_app]# curl -XPOST http://127.0.0.1:8888/hello/test-cbv/2/hello, 會員2[root@server first_django_app]# curl -XPOST http://127.0.0.1:8888/hello/test-cbv/4/hello, spyinx-0[root@server first_django_app]# curl -XPOST http://127.0.0.1:8888/hello/test-cbv/9/hello, spyinx-5[root@server first_django_app]# curl -XGET http://127.0.0.1:8888/hello/test-cbv/9/hello, get[root@server first_django_app]# curl -XPUT http://127.0.0.1:8888/hello/test-cbv/9/hello, put[root@server first_django_app]# curl -XDELETE http://127.0.0.1:8888/hello/test-cbv/9/hello, delete可以看到在 POST 請求中,我們通過傳遞主鍵值,就能返回 Member 表中對應記錄中的 name 字段值,這一功能正是由SingleObjectMixin 中的 get_object() 方法提供的。通過繼承這個查詢功能,我們就不用再使用 ORM 模型進行查找了,這簡化了我們的代碼。當然,這只能滿足一小部分的場景,對于更多復雜的場景,我們還是需要實現自己的邏輯,我們也可以把復雜的功能拆成各種 mixin,然后相關組合繼承,這樣可以很好的復用代碼,這是一種良好的編碼方式。
確定安裝成功后我們創建一個 minimal.py 文件,并寫入下面的代碼:from flask import Flaskapp = Flask(__name__)首先,導入類 flask.Flask,實例化創建一個 Flask 應用,第一個參數是 Flask 應用的名稱。__name__ 是一個標識 Python 模塊的名字的變量:如果當前模塊是主模塊,那么此模塊名字就是 __main__;如果當前模塊是被 import 的,則此模塊名字為文件名。@app.route('/')def hello_world(): return '<b>Hello World</b>'然后,定義函數 hello_world,它返回一段 html 文本。app.route(’/’) 返回一個裝飾器,裝飾器來為函數 hello_world 綁定對應的 URL,當用戶在瀏覽器訪問這個 URL 的時候,就會觸發這個函數,獲取返回值。if __name__ == '__main__': app.run()如果當前模塊是主模塊,則變量 __name__ 為 '__main__,此時調用 run() 方法啟動 Flask 應用。運行該程序,在瀏覽器中輸入 localhost:5000,瀏覽器顯示如下:在控制臺中,Flask 應用輸出如下:$ python3 hello.py * Serving Flask app "hello" (lazy loading) * Environment: production Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)127.0.0.1 - - [20/Jul/2020 08:26:47] "GET / HTTP/1.1" 200 -127.0.0.1 - - [20/Jul/2020 08:26:47] "GET /favicon.ico HTTP/1.1" 404 -這樣,我們就已經搭建好了一個最簡單的 Flask 應用。
實現 HTTP 請求操作urllib:提供操作 URL 的功能requests:基于 urllib 的 HTTP 請求庫,發出一個 HTTP 請求,等待服務器響應的網頁selenium:自動化測試工具,通過這個庫調用瀏覽器完成某些操作,比如輸入驗證碼從網頁中提取信息beautifulsoup:對 html 和 XML 進行解析,從網頁中提取信息pyquery:jQuery 的 Python 實現,能夠以 jQuery 的語法來操作解析 HTML 文檔lxml:對 html 和 XML 進行解析,支持 XPath 解析方式tesserocr:一個 OCR 庫,在遇到驗證碼的時候,可使用該庫進行識別爬蟲框架Scrapy:Scrapy 是用 python 實現的一個為了爬取網站數據,提取結構性數據而編寫的應用框架。用這個框架可以輕松爬下來如亞馬遜商品信息之類的數據PySpider: pyspider 是用 python 實現的功能強大的網絡爬蟲系統,能在瀏覽器界面上進行腳本的編寫和爬取結果的實時查看,后端使用常用的數據庫進行爬取結果的存儲,還能定時設置任務與任務優先級等Newpaper: Newspaper可以用來提取新聞、文章和內容分析
定義:protocols() 屬性就是對接口類中,所有的接口所使用的網絡協議進行一個約定,常用的網絡協議有:http、https。hidden() 屬性就是控制接口類在 Swagger 界面中的顯隱性。使用方法:protocols() 屬性默認值為空,但是 Swagger 在處理時,會默認獲取項目所采用的網絡協議,我們可以不用專門設置,如果一定要設置該屬性,則只允許設置http協議規定的屬性,不能隨意設置,http, https 這些都是被允許的。hidden() 屬性允許我們在 Swagger 生成的接口列表界面上,控制接口類是否需要顯示,默認值為 false,即接口類顯示,為true時則接口類不顯示,如下代碼段所示。@Api(hidden = true)public class UserController{ // do something...}代碼解釋:第1行,我們在 UserController 接口類的上方使用了 @Api 注解的 hidden 屬性來隱藏我們的用戶接口類。Tips :接口類的顯隱控制應該根據特定安全策略和特定客戶需求來決定顯隱,不能無故隱藏接口,更不能頻繁的切換接口的顯隱。在實際工作中,如果需要隱藏接口類則需要和項目組報備情況,說明原因。
首先展開一下 CORS 的全稱:Cross-origin resource sharing意思是跨域資源共享,這是一個 W3C 標準,從字面意思來看不難理解,它允許瀏覽器向跨域的資源發送請求,并且獲得結果數據。4.1.1 CORS 原理跨域資源共享標準新增了一組 HTTP 首部的字段,使得我們能夠通過這些字段來跨域獲取到我們所需要的資源。而要實現這一功能,我們需要前后端的配合,只有當后端實現了 CORS 功能,我們才能夠通過瀏覽器直接訪問資源。為此,我們先來看看接下來的幾個首部字段:Access-Control-Allow-Origin :表示服務端允許的請求源的域,如果是 * 表示允許所有域訪問,一般我們不建議使用 *;Access-Control-Allow-Headers: 表示預檢測中,列出了將會在正式請求的 Access-Control-Request-Headers 字段中出現的首部信息;Access-Control-Allow-Methods: 表示服務端允許的請求方法;Access-Control-Allow-Credentials: 表示服務端是否允許發送cookie。當然前端也需要設置對應的 xhr.withCredentials 來進行配合;Access-Control-Expose-Headers: 列出了可以作為響應的一部分暴露在外的頭部信息。其中,我們更為重要的當屬 Access-Control-Allow-Origin 字段,因為這個字段直接關系到你是否能夠跨域訪問資源的權限了。通常情況下,為了解決跨域問題,后端同學會設置 Access-Control-Allow-Origin 指定為我們的請求源的域,而前端代碼基本無感。4.1.2 簡單請求和非簡單請求關于 CORS ,HTTP 請求上會有一些小小區別,最直觀的區別就是會不會觸發多一次 OPTIONS 預檢測請求。我們把一些不會觸發預檢測請求的請求,稱為簡單請求,而相反,會觸發預檢測的請求則是非簡單請求。而關于如何區分簡單請求和非簡單請求,這里我就不再累贅,有興趣的同學可以讀一下 HTTP 控制訪問 。在實際的工作過程中,使用到 CORS 來解決跨域限制是非常常見的,這里我們注意一下簡單請求和非簡單請求的直觀區別即可,并在以后的工作中留意一下,而不至于懵逼于為什么多了一次 OPTIONS 請求。4.1.3 具體例子4.1.3.1 服務端核心代碼// 全局設置請求過濾app.all('*',function (req, res, next) { res.header('Access-Control-Allow-Origin', 'http://localhost:8080'); // 設置 Access-Control-Allow-Origin res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With'); // 設置 Access-Control-Allow-Headers res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS'); // 設置 Access-Control-Allow-Methods next()});// 注冊一個簡單的路由router.get("/simple/get", function(req, res) { const {a} = req.query res.send(`參數值是${a}`)});后端要做的工作就是實現 CORS 功能。正如上方代碼,我們規定了一系列 HTTP 請求頭首部字段,使得 http://localhost:8080 這個域的前端腳本擁有向服務端發起請求并取得資源的權限。4.1.3.2 前端核心代碼$.ajax({ url: 'http://localhost:8083/simple/get', method: 'GET', data : { a: 1 }}).done(data => { console.log(data)})4.1.3.3 效果可見,通過 CORS ,前端成功拿到了不同域的服務端的返回內容。4.1.4 CORS 小結CORS 是一個 W3C 的標準。使用 CORS ,我們可以使用使用常規的方式來解決前后端跨域訪問的問題。并且,大多數的工作其實也是放在了服務端上,對于前端而言,基本上可以說是無感的。當然, CORS 也是存在著一些弊端。正因為它是 W3C 中一個比較新的方案,導致了各大瀏覽器引擎沒有對其做嚴格規格的實現,由此可能產生一些不一致的情況。
服務已經可以運行了,接下來就是要編寫能被外部訪問的路由接口,http 請求分為兩種,POST 請求和 GET 請求。我們首先想實現的是一個網站登錄頁面打開的路由 /index,需要編寫一個能響應 GET 請求的路由。代碼示例:package mainimport ( "net/http")func main() { //設置訪問的路由 http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { w.Write([]byte("<h1>Hello Codey!<h1>")) } }) http.ListenAndServe("127.0.0.1:9300", nil) //設置監聽的端口}在瀏覽器中輸入127.0.0.1:9300/index:此處可以結合函數式編程的思想,將 index 的處理函數拿出來作為一個變量,代碼修改后如下所示package mainimport ( "net/http")func main() { http.HandleFunc("/index", index) //設置訪問的路由 http.ListenAndServe("127.0.0.1:9300", nil) //設置監聽的端口}func index(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { w.Write([]byte("<h1>Hello Codey!<h1>")) }} 然后修改一下輸出字符串,使其輸出一個頁面,代碼修改后如下package mainimport ( "net/http")func main() { http.HandleFunc("/index", index) //設置訪問的路由 http.ListenAndServe("127.0.0.1:9300", nil) //設置監聽的端口}func index(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { w.Write([]byte(`<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Go語言實戰1</title> </head> <body> <div> <h3>登錄</h3> <form> <div> <div> <input type="text" id="username" name="username" placeholder="請輸入賬號"> </div> </div> <div> <div> <input type="password" class="form-control" id="password" name="password" placeholder="請輸入密碼"> </div> </div> <div > <div > <button id="loginbtn" type="button" >登錄</button> </div> </div> </form> </div> </body> </html>`)) }}運行上述代碼,然后再次在瀏覽器中輸入127.0.0.1:9300/index。
本節主要是了解了 Netty 如何開發一個 Web 服務器,并且和瀏覽器進行通信,需要注意的地方有幾點,具體如下:格式要求,無論是解碼和編碼都需要嚴格按照 Http 協議格式要求,否則給瀏覽器響應數據時,瀏覽器不能識別;可以跟進 Http 格式,獲取和設置相關信息,比如:請求 IP 地址、請求 uri 地址、請求方式、請求頭內容、請求體內容等;響應頭、響應體等;靜態資源的過濾,一般情況下需要過濾掉,否則消耗服務器資源。
Restful 是由 Roy Thomas Fielding 博士在 2000 年所著的博士論文提起的,系統全面地闡述了 REST 的架構風格和設計思想,這位作者同時是 HTTP、URI等 Web 架構標準的主要設計者,因此他提出的 REST 概念得到很多人的關注和響應。
#!/usr/bin/python3from flask import Flask, request, Response, render_templateapp = Flask(__name__)從 flask 模塊中引入 request 對象,request.cookies 存儲了客戶端發送的 Cookie。從 flask 模塊中引入 Response 類,頁面處理函數返回 Response 對象,而不是字符串。Response 對象提供了 set_cookie 和 delete_cookie 等方法用于設置 Cookie 相關的 HTTP 消息頭。
Spring MVC 為了解決 HTTP 協議的無狀態性,提供了很多能適用于不同作用域需求的模型對象,從而保證程序中的數據能在開發者需要的地方出現。本節課繼續和大家聊聊 Spring MVC 中的數據模型組件。Model;ModelMap;ModelAndView。
藍圖 todos 包含有 3 個頁面:/todos/add、/todos/update、/todos/delete,代碼由如下部分構成:
Numpy(Numerical Python)是一個開源的Python科學計算庫,用于快速處理任意維度的數組。Numpy支持常見的數組和矩陣操作。Numpy 使用 ndarray 對象來處理多維數組,該對象是一個快速而靈活的大數據容器。使用 Python 列表可以存儲一維數組,通過列表的嵌套可以實現多維數組,那么為什么還需要使用Numpy 的 ndarray呢?這是因為對于同樣的數值計算任務,ndarray的計算速度比直接使用Python快很多,節約了時間。機器學習的最大特點就是大量的數據運算,效率高是一個主要要求。簡單說一下 ndarray 為什么快?ndarray 在存儲數據的時候,數據與數據的地址都是連續的,這樣就給使得批量操作數組元素時速度更快。這是因為ndarray中的所有元素的類型都是相同的,而 Python 列表中的元素類型是任意的,所以ndarray 在存儲元素時內存可以連續,而 python 原生 lis 就只能通過尋址方式找到下一個元素;ndarray支持并行化運算;Numpy 底層使用 C 語言編寫,內部解除了GIL(全局解釋器鎖),其對數組的操作速度不受 Python解釋器的限制 ,所以,其效率遠高于純 Python 代碼。關于 numpy 使用,請參考
Flask 框架中常用的鉤子總結如下:1. before_first_request在應用程序實例的第一個請求之前要運行的函數,只會運行一次。2. before_request在每個請求之前要運行的函數,對每一次請求都會執行一次。3. after_request在每個請求之后要運行的函數,對每一次請求都會執行一次。在 after_request 注冊的鉤子函數的第一個參數是 response 對象。4. teardown_request在每個請求之后要運行的函數,對每一次請求都會執行一次。在 teardown_request 注冊的鉤子函數的第一個參數是 exception 對象,指向執行請求時發生的錯誤。5. errorhandler發生一些異常時,比如 HTTP 404、HTTP 500 錯誤,或者拋出異常,就會自動調用該鉤子函數。
如果瀏覽器中請求的是一個靜態資源(瀏覽器能解釋的資源,如 Html、Css、Js、圖片……),有必要經過前端控制器嗎?當然不需要。但是,你可以試著在 WEB 項目的 根目錄下創建名為 static.html 的靜態資源,然后在瀏覽器直接請求一下(http://localhost:8888/sm-demo/static.html)。會發現請求不到,那是因為你的請求還是經過了前端控制器。所以,咱們要告訴 Spring MVC 靜態資源還是交回給 Servlet 容器處理吧, 就不勞您大駕了。打開 WebConfig 配置類,讓其實現 WebMvcConfigurer 接口;public class WebConfig implements WebMvcConfigurer{ }重寫 configureDefaultServletHandling() 方法,啟動 Servlet 的 default Servlet 來處理靜態資源;public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable();}再次請求 http://localhost:8888/sm-demo/static.html ,你應該能看到靜態頁面的內容。
本文主要介紹了 Go 語言官方提供的 http 服務,以及如何使用這個包來搭建一個 web 應用。其中需要注意區分前端發送過來的請求類型,POST 和 GET 兩個請求各自有各自的處理。
準備好靜態資源文件,我們就在 /root/test/ 下新建一個 index.html,并新建目錄 web,同時繼續在 web 目錄下分別新建 web1.html 和 web2.html 文件,具體的目錄結構如下所示:[root@server ~]# cd /root/test[root@server test]# tree ..├── index.html└── web ├── web1.html └── web2.html1 directory, 3 filesNginx 的配置如下:user root;worker_processes 2;#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events { worker_connections 1024;}http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 8080; # 靜態資源根理解 root /root/test; # 打開目錄瀏覽功能 autoindex on; # 指定網站初始頁,找index.html或者index.htm頁面 index index.html index.htm; } server { listen 8081; location /web { root /root/test/; } } server { listen 8082; location /web { alias /root/test/; } }}測試結果對于監聽的 8080 端口,我們直接使用 root 指令,指定資源的根路徑。這樣子,當我們在瀏覽器上直接訪問 http:// 服務器的 ip:8080/web/web1.html 或者 http://服務器ip:8080/web/web2.html 時,就能訪問對應的 web1.html 和 web2.html 頁面;若沒有指定靜態資源地址(即/路徑),默認會找由 index 指令指定的文件,即 index.html 或者 index.htm 文件;訪問 8080 的/地址訪問web1.html文件訪問web2.html文件對于監聽的 8081 端口,我們直接使用 root 指令,指定資源的根路徑。當請求 http://服務器ip:8081/web/xxxx 地址時,等價于訪問服務器上的靜態資源文件 /root/test/[匹配到的web]/xxxx,也即/root/test/web/xxxx,訪問 web2.html 類似;通過 8081 端口訪問 web1.html 資源通過 8081 端口訪問靜態資源 web2.html對于監聽的 8082 端口,我們使用的是 alias 指令,指定資源路徑的別名,它與 root 指令略有不同。當請求 http://服務器ip:8082/web/xxxx 地址時,等價于訪問服務器上的靜態資源文件 /root/test/xxxx,并不會將匹配到的web添加到靜態資源的路徑上,所有為了能訪問到 web1.html,我們需要使用如下的url:http://服務器ip:8082/web/web/web1.html, 訪問 web2.html 類似。結果如下:通過alias指令訪問web1.html通過alias指令訪問web2.html
連接是又控制層控制的,無連接并不是指 HTTP 不需要控制層的連接,而是指每次連接指處理一次請求,請求結束,即端口連接。這樣設計的目的,是減少開銷,提高效率。因為,TCP 控制層的連接會消耗大量的系統資源。
藍圖 users 包含有 3 個頁面:/users/login、/users/register、/users/logout,代碼由如下部分構成: