location.href遇到的400错误,url传值导致+/等特殊字符丢失

其实需求很简单,就是点击按钮后,向后台传入查询条件,然后根据查询条件获取满足条件的记录通过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( HttpServletResponse response,HttpServletRequest request){
    }


400错误一:页面提示HTTP Status 400 – Bad Request

第一种情况:后台声明了@RequestBody导致的,代码如下:

js请求如下:
location.href='/userFilter/exportUserPage.action?parameterMap='+ JSON.stringify(json);
后台接收代码
    @RequestMapping(value="/exportUserPage.action")
    public  void exportUserPage(@RequestBody Map parameterMap, HttpServletResponse response,HttpServletRequest request){

//业务代码 
    }

页面显示如下:
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){
    }

第二种情况:ajax请求data与dataType不符合

前台代码如下
function queryGeneralDataByPage(pageNow){
    var conditionJson = {};
    var json = {};    
    conditionJson[name]=value;
    
    var tableName = $('#tableName').val();
    json["condition"] = conditionJson;
    json["tableName"] = tableName;
     //查询 具体信息
    $.ajax({
        type: "POST",
        url: "../general_edit/queryGeneralDataByPage.action",
        contentType : "application/json",
        dataType:"json",
        data: json,
        success: function(resp){
            var pageNow = resp["pageNow"];
          
            $("#tableBody").html(tableBodyDiv);
        },
        error:function(XMLHttpRequest, textStatus, errorThrown){
                $.messager.alert('提示','系统内部错误,请联系管理员处理!','info');
        }
    });
}

不用看后台,这个代码一定是有问题的,因为dataType声明的方式是json,但是data实际不是json格式,所以会报400错误

修改方式就是将data修改为json,即将json修改为data: JSON.stringify(json)。


400错误二:Invalid character found in the request target


前端: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));

或者:

location.href=('../userFilter/exportUserPage.action?parameterMap='+ encodeURIComponent(encodeURIComponent(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();
        }
    }

 

如果你的访问路径中没有带项目名称,你会发现上面的代码能正常工作,但是如果访问路径中带有项目名称,则发现包404错误。此时将location.href修改为:

     location.href=encodeURI('../userFilter/exportUserPage.action?parameterMap='+ JSON.stringify(json));
 

关于上面url中需要加..的原因如下:

假设当前路径如下:http://192.168.1.138:8080/rsbi/frame/Frame.action,点击下载按钮后,会正常跳转到

http://192.168.1.138:8080/rsbi/userFilter/exportUserPage.action;但是如果location.href去掉了..,即location.href=encodeURI('/userFilter/exportUserPage.action?parameterMap='+ JSON.stringify(json));

那么点击下载按钮后会跳转到http://192.168.1.138:8080/userFilter/exportUserPage.action,丢失了项目名称rsbi,此时会无法正常调用后台方法,报404错误!!!

encodeURI传值导致的#$ ^ & * + =等特殊符号丢失问题解决

前端js代码:

var send_data={'name':'2123##%&+212'} ;
url : "searchbytext.action?send_data="+encodeURIComponent(encodeURIComponent(send_data));


为什么要两次编码的原因:后台java代码给send_data赋值的时候,本身已经使用了一次解码,不过解码的结果依然不对。所以我们可以在页面上进行两次编码操作,这样后台自动的那次就可以抵消掉一次,

后台java代码::

send_data=java.net.URLDecoder.decode(send_data,”UTF-8”);进行一次解码就好了。
//String value = URLDecoder.decode(request.getParameter(UserFilterConstants.PARAMETER_MAP), "UTF-8");


其实本质上还是对http的知识不了解,导致前后端的数据无法正确对应导致的,所以推荐书籍:

《图解Http》-看过,比较简单
http权威指南
tcp/ip详解

完整的实现excel下载功能的代码可以借鉴:https://blog.csdn.net/h2604396739/article/details/84954817

 

你可能感兴趣的:(前端)