接着Spring 5.2.2 MVC (6)--註釋控制器講基於註解控制內容。
java
3)後綴匹配typescript
默認狀況下,Spring MVC執行.*後綴模式匹配,以便映射到/person的控制器也隱蔽映射到/person.*。而後使用文件擴展名解釋請求的內容類型以用於響應(即,代替Accept
頭) - ,例如/person.pdf
, /person.xml
和其餘。編程
當瀏覽器用來發送難以一致的Accept
頭時,以這種方式使用文件擴展名是必要的。目前,這已再也不是必需的,使用Accept
頭應該是首選。json
隨着時間的推移,文件擴展名的使用已經被證實在許多方面存在問題。當使用URI變量、路徑參數和URI編碼覆蓋時,它可能會致使歧義。關於基於URL的受權和安全性的推理也變得更加困難。瀏覽器
要徹底禁用文件擴展名的使用,必須同時設置如下兩項:安全
useSuffixPatternMatching(false)
--參看PathMatchConfigurer
微信favorPathExtension(false)
--參看ContentNegotiationConfigure
app
基於URL的內容仍然頗有用(例如,在瀏覽器中鍵入URL時)。爲了實現這一點,咱們建議使用基於查詢參數的策略,以免文件擴展名帶來的大多數問題。或者,若是必須使用文件擴展名,請考慮經過ContentNegotiationConfigurer
的mediaTypes
屬性將它們限制爲顯式註冊的擴展名列表。ide
public class WebConfig implements WebMvcConfigurer {
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.mediaType("json", MediaType.APPLICATION_JSON); configurer.mediaType("xml", MediaType.APPLICATION_XML); }}
4)後綴匹配和RFD測試
反射文件下載(reflected file download,RFD)攻擊與XSS相似,它依賴於響應中反射的請求輸入(例如,查詢參數和URI變量)。然而RFD攻擊不是將JavaScript插入HTML,而是依賴於瀏覽器切換來執行下載,並在之後雙擊時將響應視爲可執行腳本。
在Spring MVC中,@ResponseBody和ResponseEntity
方法面臨風險,由於它們能夠呈現不一樣的內容類型,客戶端能夠經過URL路徑擴展請求這些內容類型。禁用後綴模式匹配和使用路徑擴展進行內容能夠下降風險,但不足以防止RFD攻擊。
爲了防止RFD攻擊,在呈現響應體以前,Spring MVC添加了一個:Content-Disposition:inline;filename=f.txt頭來建議一個固定且安全的下載文件。只有當URL路徑包含既沒有白名單也沒有爲內容顯式註冊的文件擴展名時,纔會執行此操做。然而,當URL直接輸入到瀏覽器中時,它可能會產生反作用。
默認狀況下,許多公共路徑擴展都是白名單。具備自定義HttpMessageConverter
實現的應用程序能夠註冊用於內容的文件擴展名,以免爲這些擴展名添加Content-Disposition頭。
有關RFD的其餘建議,見CVE-2015-5211。
5)Consumable 媒體Types
能夠根據請求的Content-Type縮小請求映射範圍,以下例所示:
//使用consumes屬性縮小Content-Type映射範圍。"/pets", consumes = "application/json") (path = public void addPet( Pet pet) { // ...}
consumes
屬性還支持否認表達式 - ,例如!text/plain是指除text/plain之外的任何內容類型。
能夠在類級別聲明一個共享consumes
屬性。然而,與大多數其餘請求映射屬性不一樣,當在類級別使用時,方法級別使用consumes
屬性重寫,而不是擴展類級別聲明。
MediaType
爲經常使用的媒體類型(如APPLICATION_JSON_VALUE
和APPLICATION_XML_VALUE)提供常量。
6)Producible 媒體 Types
能夠基於Accept
請求頭和控制器方法生成的內容類型列表縮小請求映射,以下例所示:
//使用products屬性縮小content type映射範圍。"/pets/{petId}", produces = "application/json") (path = public Pet getPet( String petId) { // ...}
媒體類型能夠指定字符集。例如,支持否認表達式 -!text/plain是指除「text/plain」以外的任何內容類型。
能夠在類級別聲明共享的produces
屬性。可是,與大多數其餘請求映射屬性不一樣,當在類級別使用時,方法級別生成produces
屬性重寫,而不是擴展類級別聲明。
7)Parameters, headers
能夠基於請求參數條件縮小請求映射範圍。你能夠測試是否存在請求參數(myParam),是否缺乏一個(!myPara)或特定值(myParam=myValue)。如下示例演示如何測試特定值:
//測試myParam是否等於myValue"/pets/{petId}", params = "myParam=myValue") (path = public void findPet( String petId) { // ...}
你還能夠對請求頭條件使用相同的條件,以下例所示:
//測試myHeader是否等於myvalue。"/pets", headers = "myHeader=myValue") (path = public void findPet( String petId) { // ...}
你能夠將Content-Type和Accept
與headers條件匹配,但最好使用consumers
和products
。
8)HTTP HEAD, OPTIONS
@GetMapping(和@RequestMapping(method=HttpMethod.GET))爲請求映射支持HTTP HEAD 。控制器方法不須要更改。在javax.servlet.http.HttpServlet中應用的response 封裝確保將Content-Length頭設置爲寫入的字節數(而不實際寫入響應)。
@GetMapping(和@RequestMapping(method=HttpMethod.GET))隱式映射到並支持HTTP HEAD。一個HTTP HEAD請求被看成HTTP GET來處理,只是不寫正文,而是計算字節數並設置Content-Length頭。
默認狀況下,經過將Allow
response頭設置爲全部@RequestMapping方法中列出的具備匹配URL模式的HTTP方法列表來處理HTTP選項。
對於沒有HTTP方法聲明的@RequestMapping,Allow
頭被設置爲GET、HEAD、POST、PUT、PATCH、DELETE、OPTIONS。控制器方法應始終聲明支持的HTTP方法(例如,使用HTTP方法特定的變量:@GetMapping、@PostMapping和其餘變量)。
你能夠將@RequestMapping方法映射到HTTP HEAD和HTTP OPTIONS,但在通常狀況下這是不必的。
9)自定義註解
Spring MVC支持使用組合註解進行請求映射。這些註解自己就是用@RequestMapping進行元註解的註解,用於從新聲明@RequestMapping屬性的一個子集(或所有),具備更窄、更具體的用途。
@GetMapping
, @PostMapping
, @PutMapping
, @DeleteMapping
, 和@PatchMapping是組合註解的示例。之因此提供它們,是由於大多數控制器方法應該映射到特定的HTTP方法,而不是使用@RequestMapping,默認狀況下,它與全部HTTP方法匹配。若是須要組合註解的示例,請查看如何聲明這些註釋。
Spring MVC還支持具備自定義請求匹配邏輯的自定義請求映射屬性。這是一個更高級的選項,須要子類RequestMappingHandlerMapping
並重寫getCustomMethodCondition
方法,你能夠在該方法中檢查自定義屬性並返回本身的RequestCondition。
10)易於理解的Registrations
你能夠以編程方式註冊處理程序方法,這些方法可用於動態註冊或高級狀況,例如不一樣URL下同一處理程序的不一樣實例。如下示例註冊處理程序方法:
public class MyConfig { //爲控制器注入目標處理程序和處理程序映射。 public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler) throws NoSuchMethodException { //準備請求映射數據。 RequestMappingInfo info = RequestMappingInfo .paths("/user/{id}").methods(RequestMethod.GET).build(); //獲取處理程序方法 Method method = UserHandler.class.getMethod("getUser", Long.class); //添加註冊。 mapping.registerMapping(info, handler, method); }}
明天講 基於控制器註解的句柄方法(Handler Methods)。
敬請持續關注。
歡迎關注和轉發Spring中文社區(加微信羣,能夠關注後加我微信):
本文分享自微信公衆號 - Spring中文社區(gh_81d233bb13a4)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。