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();
}

出現的情況如下:
warning

可以看到,除了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]。感謝您的閱讀,再見!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章