Ajax傳送PUT/DELETE請求時出現錯誤的原因及解決方案
本文講什麼?
大家應該都知道.在HTTP中,規定了很多種請求方式,包括POST,PUT,GET,DELETE等.每一種方式都有這種方式的獨特的用處,根據英文名稱,我們能夠很清楚的知道DELETE方法的作用—-刪除請求.而其他的,根據單詞並不能準確的知道他們想表達的意思.本文要講的並不是HTTP協議,主要是分析一下發送Ajax(非同步請求)的時候,為什麼使用GET和POST方式傳送可以接收到資料,而使用DELETE和PUT方法無法傳送請求的問題出現原因,當然還是要給出解決辦法的.
出現此問題的現象
既然要解決這個問題,那麼我們肯定要知道出現這個問題的現象是怎麼樣子的.
一般情況下,我們使用Rest風格的URI時,也就是使用HTTP協議請求方式的動詞,來表示對資源的操作(GET(查詢),POST(新增),PUT(修改),DELETE(刪除))
既然會出現這個令人頭痛的問題,那麼我們為什麼還要用這種Rest風格的URI呢?
REST 是一種軟體架構的編碼風格,是根據網路應用而去設計和開發的一種可以降低開發複雜度的編碼方式,並且可以提高程式的可伸縮性(增減問題)
可以解決的問題:
1) 查詢條件多,多種限制條件,分頁引數等。
2) 批量操作,解決共性問題
本文中不再詳細去解釋使用Rest風格的URI的原因,感興趣的同學可以自己查閱相關的資料.
- 使用Ajax傳送PUT(修改)請求
我們測試使用的是一個更新方法,利用主鍵更新員工的資訊,使用特定的PUT請求.
前端程式碼如下:
$.ajax({
url: "${pageContext.request.contextPath}/app/" + empId,
type: "PUT",
data: $("#app form").serialize(),
success: function (result) {
alert(傳送成功!);
}
error:function(){
alert("資料傳送失敗!");
}
});
後端程式碼如下:
後端程式碼非常簡單,主要就是接收從前端傳回的值,然後利用對應的id更新資料.
/**
* 員工更新資訊
*
* @param employee
* @return
*/
@RequestMapping (value = "/empl/{empId}", method = RequestMethod.PUT)
@ResponseBody
public Message updateEmployee(Employee employee) {
System.out.println(employee);
employeeService.updateEmployee(employee);
return Message.success();
}
出現的情況如下:
可以看到,除了id正常被接收到意外,其他的值全部為null,按道理說SpringMVC會自動把資料封裝到對應欄位中,form表單中的資料肯定是沒有問題的,排除寫錯欄位這一條.那麼只能是值傳遞的時候出現的問題了.
使用瀏覽器F12檢視network時,發現數據已經被封裝到了實體資訊中,問題究竟是在哪呢?
出現問題的原因
這個問題其實是Tomcat的問題.
實際上,Tomcat把請求的資料(實體資訊中的資料)封裝成一個Map(鍵值對形式),request.getParameter(“”)就從map中取值,而SpringMVC會把每個屬性的值呼叫getParameter方法封裝,而Tomcat看到是PUT請求則不會封裝請求資料到map,只有POST形式的請求才會封裝到請求體。
為什麼會出現這種情況呢?
實際上這是因為在設計Tomcat的時候就出現的問題.在Tomcat的原始碼的Request.java類中,大約是3111行左右的程式碼,有這樣的一段程式碼.
在下面這個方法中:
有如下程式碼:
這一段程式碼的作用是獲取聯結器,再判斷請求的方法是否在規定的方法之中,如果存在,則繼續,如果不存在,則直接返回,不進行資料的封裝.與我們設定的方法比對的就是程式碼中的方法,這個方法是POST,所以我們的PUT方法和POST肯定是不一樣的,最後只能是返回.於是就出現了上面的情況.
解決方案
這個問題有兩種解決方案,第一種比較複雜,第二種比較簡單,正常我們肯定是使用第二種的,當然並不排除使用第一種方式的場景.
方案一
- 配置web.xml檔案
<!--使用Rest風格的URI-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在傳送Ajax請求的時候,使用如下的格式:
$.ajax({
url: "${pageContext.request.contextPath}/emp/" + id,
type: "POST",
data: $("#app form").serialize() +"&_method=PUT",
success: function (result) {
alert("操作成功!");
}
});
可以看到不同的地方,首先配置HiddenHttpMethodFilter,這個類可以把POST轉換成對應的_method=?的?號中的內容,從而實現請求.當然每次寫Ajax請求的時候,都需要協商method欄位,便於解析.
方案二
方案二就比較簡單了.只需要一個簡單的web.xml的配置.
<!--配置SpringMVC,把PUT或者DELETE請求轉換成POST-->
<filter>
<filter-name>HttpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
然後就可以很自然的使用Ajax請求而不需要做任何的處理.
$.ajax({
url: "${pageContext.request.contextPath}/emp/" + id,
type: "PUT",
data: $("#app form").serialize(),
success: function (result) {
alert("操作成功!");
}
});
以上,就是本文的全部內容,謝謝閱讀!
結語
好了,這次的文章就到這裡了,如果你喜歡我的文章,請關注我,可以點個贊,支援一下我,或者給一些評論,這是對原創作者最大的支援!
也歡迎您關注我的微信公眾號:最高許可權位元流,可以在後臺回覆”專案實戰”,”java”來獲取相關資料進行學習,有任何問題,也可以郵件聯絡我:[email protected]。感謝您的閱讀,再見!