1. 程式人生 > >location.href遇到的400錯誤

location.href遇到的400錯誤

其實需求很簡單,就是點選按鈕後,向後臺傳入查詢條件,然後根據查詢條件獲取滿足條件的記錄通過excel下載。

方案一:使用ajax方式不可以原因
匯出excel算是檔案下載了,後臺需要向前臺(瀏覽器)寫檔案流,而ajax請求獲取的資料的都是字串(此點當時在除錯頁面的時候,Response響應中滿是亂碼的字串文字),它沒法解決後臺返回的檔案流,但是瀏覽器可以。
換句話說 ajax貌似實現不了檔案下載的功能,所以使用window.location.href直接地址重定向


方案二:location.href  
js請求如下:
location.href='/userFilter/exportUserPage.action?parameterMap='+ JSON.stringify(json);
後臺接收程式碼
    @RequestMapping(value="/exportUserPage.action")
    public  void exportUserPage(@RequestBody Map parameterMap, HttpServletResponse response,HttpServletRequest request){

//業務程式碼 
    }
400錯誤一
頁面顯示如下:
HTTP Status 400 – Bad Request
Type Status Report

Description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
伺服器不能或不會處理請求,因為某些東西被認為是客戶端錯誤(例如,格式錯誤的請求語法、無效的請求訊息框架或欺騙性的請求路由)。

怎麼理解@RequestBody????
@RequestBody使用方式:
@requestBody註解常用來處理content-type不是預設的application/x-www-form-urlcoded編碼的內容,比如說:application/json或者是application/xml等。一般情況下來說常用其來處理application/json型別。

    通過@requestBody可以將請求體中的JSON字串繫結到相應的bean上,當然,也可以將其分別繫結到對應的字串上。
    例如說以下情況:
    $.ajax({
        url:"/login",
        type:"POST",
        data:'{"userName":"admin","pwd","admin123"}',
        content-type:"application/json charset=utf-8",
        success:function(data){
          alert("request success ! ");
        }
    });

    @requestMapping("/login")
    public void login(@requestBody String userName,@requestBody String pwd){
      System.out.println(userName+" :"+pwd);
    }
    這種情況是將JSON字串中的兩個變數的值分別賦予了兩個字串,但是呢假如我有一個User類,擁有如下欄位:
      String userName;
      String pwd;
    那麼上述引數可以改為以下形式:@requestBody User user 這種形式會將JSON字串中的值賦予user中對應的屬性上
    需要注意的是,JSON字串中的key必須對應user中的屬性名,否則是請求不過去的。
借鑑與:http://www.cnblogs.com/qiankun-site/p/5774300.html

解決方案去掉後臺處理的@RequestBody Map parameterMap
修改後的前後端程式碼如下:

js請求:
location.href='/userFilter/exportUserPage.action?parameterMap='+ JSON.stringify(json);
後臺接收程式碼
    @RequestMapping(value="/exportUserPage.action")
    public  void exportUserPage( HttpServletResponse response,HttpServletRequest request){
    }
400錯誤二
前端:Failed to load resource: the server responded with a status of 400 ()
後臺: java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986,
翻譯:請求目標中發現無效字元。在RFC 7230和RFC 3986中定義了有效字元。

必須指出的是這個錯是tomcat報的。。。。。。

接下來我們來看看RFC 3986中到底是怎麼規範的
RFC3986文件規定,Url中只允許包含英文字母(a-zA-Z)、數字(0-9)、-_.~4個特殊字元以及所有保留字元。RFC3986文件對Url的編解碼問題做出了詳細的建議,指出了哪些字元需要被編碼才不會引起Url語義的轉變,以及對為什麼這些字元需要編碼做出了相應的解釋。
US-ASCII字符集中沒有對應的可列印字元:Url中只允許使用可列印字元。US-ASCII碼中的10-7F位元組全都表示控制字元,這些字元都不能直接出現在Url中。同時,對於80-FF位元組(ISO-8859-1),由於已經超出了US-ACII定義的位元組範圍,因此也不可以放在Url中

這個問題其實就是你傳入的url和引數中存在不符合規範的字元。

解決方案:
encodeURI(),用來encode整個URL,不會對下列字元進行編碼:+ : / ; ?&。它只會對漢語等特殊字元進行編碼 
encodeURIComponent (),用來enode URL中想要傳輸的字串,它會對所有url敏感字元進行encode 

所以
js中:
     location.href=encodeURI('/userFilter/exportUserPage.action?parameterMap='+ JSON.stringify(json));
後臺:
    @RequestMapping(value="/exportUserPage.action")
    public  void exportUserPage( HttpServletResponse response,HttpServletRequest request){

        Map parameterMap = new HashMap();

        try {
            // 前端編碼,這裡需要解碼取值,parameterMap對應前端引數的名稱
            String value = URLDecoder.decode(request.getParameter("parameterMap"), "UTF-8");
            System.out.println("value");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

 
其實本質上還是對http的知識不瞭解,導致前後端的資料無法正確對應導致的,所以推薦書籍:

《圖解Http》
http權威指南
tcp/ip詳解

完整的實現excel下載功能的程式碼可以借鑑:https://blog.csdn.net/h2604396739/article/details/84954817