Web請求與回應

Web的作業原理可以分為以下幾個步驟:
-
輸入URL:Web客戶端使用Web瀏覽器輸入所需訪問的URL(統一資源定位符),
-
建立連接:Web瀏覽器與Web服務器之間建立TCP/IP連接,以便傳輸資料,
-
發送HTTP請求:Web瀏覽器向Web服務器發送HTTP請求,請求所需的Web資源,
-
接收HTTP回應:Web服務器接收HTTP請求,并通過HTTP回應將Web資源發送給Web瀏覽器,
-
渲染Web頁面:Web瀏覽器接收HTTP回應,并根據所收到的資料渲染Web頁面,以便呈現給用戶,
-
關閉連接:Web瀏覽器和Web服務器之間的TCP/IP連接被關閉,
什么是 HTTP 請求?
HTTP(超文本傳輸協議)是一種用于 Web 服務器和客戶端(瀏覽器)之間通信以通過 Internet 傳輸資料的協議, HTTP 請求是客戶端向服務器發送的請求特定資源(如網頁、影像或視頻)的訊息, HTTP 請求方法決定了請求的型別,例如 GET、POST、PUT、DELETE、HEAD、OPTIONS、CONNECT、TRACE 等,
HTTP請求的結構:
HTTP 請求由請求行、標頭和可選的訊息正文組成,
請求行包括 HTTP 方法、所請求資源的 URL(統一資源定位符)以及所使用的 HTTP 版本,
標頭提供有關請求的其他資訊,例如用戶代理、請求的內容型別和可接受的編碼格式,
訊息正文是可選的,包含資料,例如表單資料或 JSON ,
HTTP請求方法:
HTTP 定義了各種請求方法,指示要對 URL 標識的資源執行的操作,最常見的 HTTP 請求方法是:
-
GET:從服務器獲取資源,例如網頁或影像,
-
POST:將資料提交給服務器進行處理,例如表單提交或檔案上傳,
-
PUT:用新資料更新服務器上的現有資源,
-
DELETE:從服務器中洗掉資源,
-
HEAD:檢索資源的標頭,不帶訊息正文,
-
OPTIONS:用于獲取當前URL所支持的方法,若請求成功,則它會在HTTP頭中包含一個名為“Allow”的頭,值是所支持的方法,如“GET, POST”,
-
CONNECT:建立到資源的網路連接,例如代理服務器,
-
TRACE:回顯接收到的請求訊息,用于除錯目的, HTTP 標頭:
HTTP 標頭用于提供有關 HTTP 請求或回應的附加資訊,它們是由冒號分隔的鍵值對,包含在請求或回應訊息中, Header有多種型別,例如通用Header、請求Header、回應Header和物體Header,一些常見的標頭包括:
-
User-Agent:向訪問網站提供你所使用的瀏覽器型別、作業系統及版本、CPU 型別、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等資訊的標識
-
Accept:指定客戶端接受的內容型別,
-
Content-Type:指定請求或回應訊息中內容的型別,
-
Content-Length:指定訊息體的長度,以位元組為單位,
-
Cache-Control:指定回應的快取指令,例如 max-age 和 must-revalidate,
-
Authorization:指定請求的身份驗證憑據, HTTP 訊息體body:
HTTP 訊息正文是 HTTP 請求或回應的可選部分,包含各種格式的資料,例如 HTML、JSON、XML 或二進制資料,在請求中,訊息正文包含要發送到服務器的資料,例如表單資料或檔案上傳,在回應中,訊息正文包含所請求資源的實際內容,例如 HTML 頁面或影像,
總之,了解 http 請求和回應的基礎知識對于 Web 開發以及 Web 服務器和客戶端之間的通信至關重要,通過了解如何構建 HTTP 請求、各種請求方法、標頭的使用以及可選的訊息正文,開發人員可以有效地與服務器通信并創建健壯的 Web 應用程式,
什么是 HTTP 回應?
HTTP回應是由服務器向客戶發送的對請求的回應, HTTP 回應包含以下組件:
-
HTTP版本
-
狀態碼
-
狀態訊息
-
回應頭
-
回應體
1、HTTP版本
回應中使用的 HTTP 版本在回應的第一行中指定,例如:
HTTP/1.1 200 OK
這指定使用 HTTP 版本 1.1 發送回應,
2、狀態碼
狀態代碼表示所請求操作的結果, HTTP 定義了五類狀態碼:
-
資訊提示 (100-199)
-
成功 (200-299)
-
重定向 (300-399)
-
客戶端錯誤 (400-499)
-
服務器錯誤 (500-599) 每個狀態碼都是一個三位數字,它包含在HTTP版本之后的回應的第一行中,例如:
HTTP/1.1 200 OK
這表明操作成功,請求的資源包含在回應正文中,
3、狀態資訊
狀態訊息是對狀態代碼的描述,它包含在狀態代碼之后的回應的第一行中,例如:
HTTP/1.1 404 Not Found
這表示未找到請求的資源,狀態訊息提供了問題的簡短描述,
4、回應頭
回應標頭包含有關回應的元資料,它們類似于請求標頭,但提供有關回應而不是請求的資訊,回應標頭可以包括有關服務器、快取策略、cookie 等的資訊,
回應標頭包含在第一行之后的回應中,每個標頭都是一個由冒號分隔的鍵值對,例如:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1274
Server: Apache
在此示例中,回應包含三個標頭:Content-Type、Content-Length 和 Server,
5、回應體
回應正文包含請求的資源或錯誤訊息,如果找不到請求的資源,回應正文的格式取決于回應中包含的 Content-Type 標頭,例如,如果 Content-Type 標頭設定為“text/html”,則回應正文應包含 HTML 代碼,
回應主體包含在回應標頭之后的回應中,如果回應主體很大,它可能會被拆分成多個資料包,
HTTP 請求和回應的技術點
HTTP 請求和回應有幾個開發人員需要注意的技術點,這些技術點決定了請求和回應如何在客戶端和服務器之間構建和傳輸,
1、請求和回應標頭
HTTP 請求和回應包含提供有關請求或回應的附加資訊的標頭,標頭是在訊息標頭中發送的鍵值對,它們用于傳達有關請求或回應的元資料, Headers 有多種型別,包括通用 Headers、請求 Headers、回應 Headers 和物體 Headers,
通用標頭適用于請求和回應,并提供有關整個訊息的資訊,例如訊息格式、發送日期和時間以及訊息是否可以快取,
請求標頭用于提供有關發出請求的客戶端的資訊,例如用戶代理(用于訪問服務器的軟體)、接受的內容型別以及用于壓縮訊息正文的編碼,
回應頭提供了服務器對客戶端請求的回應資訊,如回應的內容型別、訊息體的長度、回應是否可以快取等,
物體標頭用于提供有關訊息正文的資訊,例如內容長度和內容編碼,
2、HTTP 方法
HTTP 請求使用一組方法來指定要對 URL 中標識的資源執行的所需操作,最常見的 HTTP 方法是 GET、POST、PUT、DELETE 和 HEAD,
-
GET:用于從服務器檢索資料,
-
POST:用于向服務器發送資料以創建或更新資源,
-
PUT:用于更新服務器上的現有資源,
-
DELETE:用于從服務器中洗掉資源,
-
HEAD:用于檢索資源的標頭,而不是訊息正文, HTTP 狀態碼 HTTP 回應包括指示請求狀態的狀態代碼,有五類狀態代碼,每類都有自己的一組代碼:
? 1xx: 資訊 - 表示服務器已收到請求并正在繼續處理它, ? 2xx: 成功——表示請求被成功接收、理解和接受, ? 3xx: 重定向——表示客戶端需要采取進一步的行動來完成請求, ? 4xx: 客戶端錯誤 - 表示請求包含錯誤的語法或無法實作, ? 5xx: 服務器錯誤 - 表示服務器未能滿足有效請求, 最常見的狀態代碼是 200 OK(請求成功)、404 Not Found(未找到請求的資源)和 500 Internal Server Error(服務器在處理請求時遇到錯誤),
3、Cookies
HTTP 請求和回應還可以包括 cookie,它們是存盤在客戶端計算機上的小文本檔案, Cookie 用于存盤有關客戶端偏好或之前與服務器互動的資訊,服務器可以使用 cookie 來識別客戶端并提供定制的內容,
4、快取
HTTP 請求和回應還可以被快取,這意味著客戶端或中間服務器可以存盤回應的副本以備將來使用,快取有助于減少網路流量并提高性能,但如果快取的內容過時或陳舊,也會導致問題,
作者博客:
yhttps://blog.51cto.com/sdwml/6104070
1.基于SpringBoot請求
請求(HttpServletRequest):獲取請求資料
在瀏覽器地址輸入地址,點擊回車請求服務器,這個程序就是一個請求程序,
1.1簡單引數
1.1.1原始方式
在原始的Web程式當中,需要通過Servlet中提供的API:HttpServletRequest(請求物件),獲取請求的相關資訊,比如獲取請求引數:
Tomcat接受到Http請求時:把請求的相關資訊封裝到HttpServletRequest物件中,
在Controller中,我們要想獲取Request物件,可以直接在方法的形參中宣告HttpServletRequest物件,然后就可以通過該物件來獲取請求資訊:
//根據指定的引數名獲取請求引數的資料值
String request.getParameter("引數名")
@RestController
public class RequestController {
//原始方式
@RequestMapping("/simpleParam")
public String simpleParam(HttpServletRequest request){
// http://localhost:8080/simpleParam?name=Tom&age=10
// 請求引數: name=Tom&age=10 (有2個請求引數)
// 第1個請求引數: name=Tom 引數名:name,引數值:Tom
// 第2個請求引數: age=10 引數名:age , 引數值:10
?
String name = request.getParameter("name");//name就是請求引數名
String ageStr = request.getParameter("age");//age就是請求引數名
?
int age = Integer.parseInt(ageStr);//需要手動進行型別轉換
System.out.println(name+" : "+age);
return "OK";
}
}
1.1.2SpringBoot方式
在Springboot的環境中,對原始的API進行了封裝,接收引數的形式更加簡單, 如果是簡單引數,引數名與形參變數名相同,定義同名的形參即可接收引數,
@RestController
public class RequestController {
// http://localhost:8080/simpleParam?name=Tom&age=10
// 第1個請求引數: name=Tom 引數名:name,引數值:Tom
// 第2個請求引數: age=10 引數名:age , 引數值:10
//springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(String name , Integer age ){//形參名和請求引數名保持一致
System.out.println(name+" : "+age);
return "OK";
}
}
結論:不論是GET請求還是POST請求,對于簡單引數來講,只要保證==請求引數名和Controller方法中的形參名保持一致==,就可以獲取到請求引數中的資料值,
1.1.3引數名不一致
如果方法形參名稱與請求引數名稱不一致,controller方法中的形參還能接收到請求引數值嗎?
@RestController
public class RequestController {
// http://localhost:8080/simpleParam?name=Tom&age=20
// 請求引數名:name
?
//springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(String username , Integer age ){//請求引數名和形參名不相同
System.out.println(username+" : "+age);
return "OK";
}
}
答案:運行沒有報錯, controller方法中的username值為:null,age值為20
-
結論:對于簡單引數來講,請求引數名和controller方法中的形參名不一致時,無法接收到請求資料
那么如果我們開發中,遇到了這種請求引數名和controller方法中的形參名不相同,怎么辦?
解決方案:可以使用Spring提供的@RequestParam注解完成映射
在方法形參前面加上 @RequestParam 然后通過value屬性執行請求引數名,從而完成映射,代碼如下:
@RestController
public class RequestController {
// http://localhost:8080/simpleParam?name=Tom&age=20
// 請求引數名:name
?
//springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam("name") String username , Integer age ){
System.out.println(username+" : "+age);
return "OK";
}
}
注意事項:
@RequestParam中的required屬性默認為true(默認值也是true),代表該請求引數必須傳遞,如果不傳遞將報錯
如果該引數是可選的,可以將required屬性設定為false
@RequestMapping("/simpleParam") public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age){ System.out.println(username+ ":" + age); return "OK"; }
1.2物體引數
在使用簡單引數做為資料傳遞方式時,前端傳遞了多少個請求引數,后端controller方法中的形參就要書寫多少個,如果請求引數比較多,通過上述的方式一個引數一個引數的接收,會比較繁瑣,
此時,我們可以考慮將請求引數封裝到一個物體類物件中, 要想完成資料封裝,需要遵守如下規則:請求引數名與物體類的屬性名相同
1.2.1簡單物體類物件
定義POJO物體類:
public class User {
private String name;
private Integer age;
?
public String getName() {
return name;
}
?
public void setName(String name) {
this.name = name;
}
?
public Integer getAge() {
return age;
}
?
public void setAge(Integer age) {
this.age = age;
}
?
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
?
Controller方法
@RestController
public class RequestController {
//物體引數:簡單物體物件
@RequestMapping("/simplePojo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}
}
1.2.2復雜物體類物件
上面我們講的呢是簡單的物體物件,下面我們在來學習下復雜的物體物件,
復雜物體物件指的是,在物體類中有一個或多個屬性,也是物體物件型別的,如下:
-
User類中有一個Address型別的屬性(Address是一個物體類)
復雜物體物件的封裝,需要遵守如下規則:
-
請求引數名與形參物件屬性名相同,按照物件層次結構關系即可接收嵌套物體類屬性引數,
定義POJO物體類:
-
Address物體類
public class Address {
private String province;
private String city;
?
public String getProvince() {
return province;
}
?
public void setProvince(String province) {
this.province = province;
}
?
public String getCity() {
return city;
}
?
public void setCity(String city) {
this.city = city;
}
?
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
-
User物體類
public class User {
private String name;
private Integer age;
private Address address; //地址物件
?
public String getName() {
return name;
}
?
public void setName(String name) {
this.name = name;
}
?
public Integer getAge() {
return age;
}
?
public void setAge(Integer age) {
this.age = age;
}
?
public Address getAddress() {
return address;
}
?
public void setAddress(Address address) {
this.address = address;
}
?
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
Controller方法:
@RestController
public class RequestController {
//物體引數:復雜物體物件
@RequestMapping("/complexPojo")
public String complexPojo(User user){
System.out.println(user);
return "OK";
}
}
Postman測驗:

1.3陣列集合引數
陣列集合引數的使用場景:在HTML的表單中,有一個表單項是支持多選的(復選框),可以提交選擇的多個值,
后端程式接收上述多個值的方式有兩種:
-
陣列
-
集合
1.3.1陣列
陣列引數:請求引數名與形引陣列名稱相同且請求引數為多個,定義陣列型別形參即可接收引數
Controller方法:
@RestController
public class RequestController {
//陣列集合引數
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println(Arrays.toString(hobby));
return "OK";
}
}
Postman測驗:
在前端請求時,有兩種傳遞形式:
方式一:http://localhost:8080/arrayParam?hobby=game&hobby=java
方式二:http://localhost:8080/arrayParam?hobby=game,java
1.3.2集合
集合引數:請求引數名與形參集合物件名相同且請求引數為多個,@RequestParam 系結引數關系
默認情況下,請求中引數名相同的多個值,是封裝到陣列,如果要封裝到集合,要使用@RequestParam系結引數關系
Controller方法:
@RestController
public class RequestController {
//陣列集合引數
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
System.out.println(hobby);
return "OK";
}
}
Postman測驗:
方式一:http://localhost:8080/listParam?hobby=game&hobby=java
方式二:http://localhost:8080/listParam?hobby=game,java
1.4日期函式
上述演示的都是一些普通的引數,在一些特殊的需求中,可能會涉及到日期型別資料的封裝,比如,如下需求:
因為日期的格式多種多樣(如:2022-12-12 10:05:45 、2022/12/12 10:05:45),那么對于日期型別的引數在進行封裝的時候,需要通過@DateTimeFormat注解,以及其pattern屬性來設定日期的格式,
-
@DateTimeFormat注解的pattern屬性中指定了哪種日期格式,前端的日期引數就必須按照指定的格式傳遞,
-
后端controller方法中,需要使用Date型別或LocalDateTime型別,來封裝傳遞的引數,
Controller方法:
@RestController
public class RequestController {
//日期時間引數
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
System.out.println(updateTime);
return "OK";
}
}
1.5JSON引數
如果是比較復雜的引數,前后端通過會使用JSON格式的資料進行傳輸, (JSON是開發中最常用的前后端資料互動方式)
我們學習JSON格式引數,主要從以下兩個方面著手:
-
Postman在發送請求時,如何傳遞json格式的請求引數
-
在服務端的controller方法中,如何接收json格式的請求引數
Postman發送JSON格式資料:

服務端Controller方法接收JSON格式資料:
-
傳遞json格式的引數,在Controller中會使用物體類進行封裝,
-
封裝規則:JSON資料鍵名與形參物件屬性名相同,定義POJO型別形參即可接收引數,需要使用 @RequestBody標識,
-
@RequestBody注解:將JSON資料映射到形參的物體類物件中(JSON中的key和物體類中的屬性名保持一致)
物體類:Address
public class Address {
private String province;
private String city;
//省略GET , SET 方法
}
物體類:User
public class User {
private String name;
private Integer age;
private Address address;
//省略GET , SET 方法
}
Controller方法:
@RestController
public class RequestController {
//JSON引數
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}
}
Postman測驗:

1.6路徑引數
傳統的開發中請求引數是放在請求體(POST請求)傳遞或跟在URL后面通過?key=value的形式傳遞(GET請求),
在現在的開發中,經常還會直接在請求的URL中傳遞引數,例如:
http://localhost:8080/user/1
http://localhost:880/user/1/0
上述的這種傳遞請求引數的形式呢,我們稱之為:路徑引數,
學習路徑引數呢,主要掌握在后端的controller方法中,如何接收路徑引數,
路徑引數:
-
前端:通過請求URL直接傳遞引數
-
后端:使用{…}來標識該路徑引數,需要使用@PathVariable獲取路徑引數
Controller方法:
@RestController
public class RequestController {
//路徑引數
@RequestMapping("/path/{id}")
public String pathParam(@PathVariable Integer id){
System.out.println(id);
return "OK";
}
}
傳遞多個路徑引數:
Controller方法:
@RestController
public class RequestController {
//路徑引數
@RequestMapping("/path/{id}/{name}")
public String pathParam2(@PathVariable Integer id, @PathVariable String name){
System.out.println(id+ " : " +name);
return "OK";
}
}
2.基于SpringBoot回應
回應(HttpServletReponse):設定回應資料
服務器根據瀏覽器發送的請求,放回資料到瀏覽器在網頁上進行顯示的程序就叫回應,
2.1@ResponseBody
controller方法中的return的結果,怎么就可以回應給瀏覽器呢?
答案:使用@ResponseBody注解
@ResponseBody注解:
-
型別:方法注解、類注解
-
位置:書寫在Controller方法上或類上
-
作用:將方法回傳值直接回應給瀏覽器
-
如果回傳值型別是物體物件/集合,將會轉換為JSON格式后在回應給瀏覽器
-
但是在我們所書寫的Controller中,只在類上添加了@RestController注解、方法添加了@RequestMapping注解,并沒有使用@ResponseBody注解,怎么給瀏覽器回應呢?
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
System.out.println("Hello World ~");
return "Hello World ~";
}
}
原因:在類上添加的@RestController注解,是一個組合注解,
-
@RestController = @Controller + @ResponseBody
@RestController原始碼:
@Target({ElementType.TYPE}) //元注解(修飾注解的注解)
@Retention(RetentionPolicy.RUNTIME) //元注解
@Documented //元注解
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
結論:在類上添加@RestController就相當于添加了@ResponseBody注解,
-
類上有@RestController注解或@ResponseBody注解時:表示當前類下所有的方法回傳值做為回應資料
-
方法的回傳值,如果是一個POJO物件或集合時,會先轉換為JSON格式,在回應給瀏覽器
-
下面我們來測驗下回應資料:
@RestController
public class ResponseController {
//回應字串
@RequestMapping("/hello")
public String hello(){
System.out.println("Hello World ~");
return "Hello World ~";
}
//回應物體物件
@RequestMapping("/getAddr")
public Address getAddr(){
Address addr = new Address();//創建物體類物件
addr.setProvince("廣東");
addr.setCity("深圳");
return addr;
}
//回應集合資料
@RequestMapping("/listAddr")
public List<Address> listAddr(){
List<Address> list = new ArrayList<>();//集合物件
Address addr = new Address();
addr.setProvince("廣東");
addr.setCity("深圳");
?
Address addr2 = new Address();
addr2.setProvince("陜西");
addr2.setCity("西安");
?
list.add(addr);
list.add(addr2);
return list;
}
}
在服務端回應了一個物件或者集合,那私前端獲取到的資料是什么樣子的呢?我們使用postman發送請求來測驗下,測驗效果如下:


2.2統一回應結果
大家有沒有發現一個問題,我們在前面所撰寫的這些Controller方法中,回傳值各種各樣,沒有任何的規范,
如果我們開發一個大型專案,專案中controller方法將成千上萬,使用上述方式將造成整個專案難以維護,那在真實的專案開發中是什么樣子的呢?
在真實的專案開發中,無論是哪種方法,我們都會定義一個統一的回傳結果,方案如下:
前端:只需要按照統一格式的回傳結果進行決議(僅一種決議方案),就可以拿到資料,
統一的回傳結果使用類來描述,在這個結果中包含:
-
回應狀態碼:當前請求是成功,還是失敗
-
狀態碼資訊:給頁面的提示資訊
-
回傳的資料:給前端回應的資料(字串、物件、集合)
定義在一個物體類Result來包含以上資訊,代碼如下:
public class Result {
private Integer code;//回應碼,1 代表成功; 0 代表失敗
private String msg; //回應碼 描述字串
private Object data; //回傳的資料
public Result() { }
public Result(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = https://www.cnblogs.com/yaomagician/archive/2023/03/23/data;
}
?
public Integer getCode() {
return code;
}
?
public void setCode(Integer code) {
this.code = code;
}
?
public String getMsg() {
return msg;
}
?
public void setMsg(String msg) {
this.msg = msg;
}
?
public Object getData() {
return data;
}
?
public void setData(Object data) {
this.data = data;
}
?
//增刪改 成功回應(不需要給前端回傳資料)
public static Result success(){
return new Result(1,"success",null);
}
//查詢 成功回應(把查詢結果做為回傳資料回應給前端)
public static Result success(Object data){
return new Result(1,"success",data);
}
//失敗回應
public static Result error(String msg){
return new Result(0,msg,null);
}
}
改造Controller:
@RestController
public class ResponseController {
//回應統一格式的結果
@RequestMapping("/hello")
public Result hello(){
System.out.println("Hello World ~");
//return new Result(1,"success","Hello World ~");
return Result.success("Hello World ~");
}
?
//回應統一格式的結果
@RequestMapping("/getAddr")
public Result getAddr(){
Address addr = new Address();
addr.setProvince("廣東");
addr.setCity("深圳");
return Result.success(addr);
}
?
//回應統一格式的結果
@RequestMapping("/listAddr")
public Result listAddr(){
List<Address> list = new ArrayList<>();
?
Address addr = new Address();
addr.setProvince("廣東");
addr.setCity("深圳");
?
Address addr2 = new Address();
addr2.setProvince("陜西");
addr2.setCity("西安");
?
list.add(addr);
list.add(addr2);
return Result.success(list);
}
}
使用Postman測驗:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/547876.html
標籤:其他
