测试1:测试设置返回的类型和你所设置的返回值类型不兼容:

  1. $("#get-data").on("click", function() {
  2. var request = new XMLHttpRequest();
  3. var url = "http://localhost:8083/test/controller";
  4. var method = "GET";
  5. request.open(method, url);
  6. request.responseType = "json" //设置响应类型为json,实际接口返回类型为 string "testA"
  7. request.send(null);
  8. request.onreadystatechange = function() {
  9. if (request.readyState === 4) {
  10. if (request.status == 200) {
  11. console.log(request.response); //null
  12. console.log(request.responseText); //报错,只有responseType 为 "" 或 text 时才可用
  13. }
  14. }
  15. }
  16. })

image.png

1. responseType 为 “” 或者 “text”

responseType 值设置为 “” 或者 “text” 时,XMLHttpRequest 对象的 response 是以 DOMString 对象表示的文本。此文本如果是 html格式, 可以直接innerHtml 查到页面中去
核心代码如下:

  1. var xhr = new XMLHttpRequest();
  2. xhr.responseType = responseType; //responseType 是可读可写属性, 直接通过赋值的方式设置
  3. //处理返回结果
  4. // 解析文本的方法, 如果不设置 requestType 或者设置为 "text",则 response 是一个以 DOMString 对象表示的文本。
  5. // 此文本如果是 html格式, 可以直接innerHtml 查到页面中去
  6. function parseText(xhr) {
  7. console.log(xhr)
  8. // 当requestType 为 "" 或者 "text"时,reponseText的值和response的值时完全一样的
  9. //注: reponseText 只有在 requestType 为 "" 或者 "text"时 才能使用
  10. var text = xhr.responseText;
  11. var textResponse = xhr.response;
  12. console.log("这是reponseText的值:" + text);
  13. console.log("这是textResponse的值:" + textResponse)
  14. document.getElementById("response-container").innerHTML = text; //插到文本中去
  15. document.getElementById("response-container").innerHTML = textResponse;
  16. }

2.responseType 为 arraybuffer

前端将 responseType 设置为 arraybuffer,response 是一个包含二进制数据的 JavaScript ArrayBuffer。此时返回的JavaScript ArrayBuffer对象可以有几种处理方式。
ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。它是一个字节数组,通常在其他语言中称为“byte array”。

2.1 后端返回的是二进制的字符串(没啥实际意义,看看返回结果)

后端代码:在响应头中定义 arraybuffer-type 为 text

/**
     * 响应方式为arraybuffer, 且返回的是一个 String 字符串转的 byte数组
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("arraybuffer/text")
    public byte[] arraybuffer(HttpServletRequest request, HttpServletResponse response) {
        byte[] result = "普通的字符串转成byte数组,使用arraybuffer".getBytes();
        response.setHeader("arraybuffer-type", "text");  //在响应头中标明返回的二进制数据的类型, 此处用 text 表示返回的二进制数据是一个字符串
        return result;
    }

前端代码

/**
         requestType: 请求方式
         url:请求地址
        */
        function sendRequest(event) {
            var responseType = event.data.responseType;
            var inurl = event.data.url;
            console.log(responseType);

            var xhr = new XMLHttpRequest();
            var url = $.rootPath + curModule + inurl;
            var method = "GET";
            xhr.open(method, url);

            xhr.responseType = responseType;  //responseType 是可读可写属性, 直接通过赋值的方式设置

            xhr.send(null);
            xhr.onreadystatechange = function() {
                console.log(xhr.readyState == 4 && xhr.status === 200)
                if (xhr.readyState == 4 && xhr.status === 200) {
                    parseResponse(xhr);
                }
            }

        }
        /**
        处理 responseType 为 arraybuffer 的返回结果
        */
        function parseArraybuffer(xhr) {
            var arraybufferType = xhr.getResponseHeader("arraybuffer-type");//后台设置
            console.log(arraybufferType)
            if (arraybufferType == "text") {
                textArraybuffer(xhr.response)
            } else if (arraybufferType == "file") {
                downloadFile(xhr);
            } 
        }
/**
        返回的二进制数据是 一个字符串转的 二进制 数据
        */
        function textArraybuffer(response) {
            console.log(response); 
        }

控制台输出如下
image.png

2.2 后台返回二级制的文件

后端代码:

  • 在响应头中定义 arraybuffer-type 为 file;
  • 设置filename 为获取的文件的名字
  • 设置文件类型 filetype 为文件的后缀名

    /**
    * 响应方式为arraybuffer, 且返回的是一个 图片 
    * @param request
    * @param response
    * @return
    */
    @RequestMapping("arraybuffer/image")
    public void arraybufferImage(HttpServletRequest request, HttpServletResponse response) {
       File file = new File("E:\\project\\BackEnd\\xmlhttprequest-demo\\src\\main\\resources\\static\\image\\iron-man.jpg");
       InputStream in = null;
       OutputStream out = null;
    
       String fileName = file.getName();
       String fileType = fileName.substring(fileName.lastIndexOf("."));
       response.setContentType("application/force-download;charset=UTF-8");
       response.setHeader("arraybuffer-type", "image");
       response.setHeader("filename", fileName);
       response.setHeader("filetype", fileType);
    
     //获取要下载的文件输入流
       try {
                   in = new FileInputStream(file);
                   int len = 0;
           //创建数据缓冲区
           byte[] buffer = new byte[1024];
           //通过response对象获取outputStream流
           out = response.getOutputStream();
           //将FileInputStream流写入到buffer缓冲区
           while((len = in.read(buffer)) > 0) {
               //使用OutputStream将缓冲区的数据输出到浏览器
               out.write(buffer,0,len);
           }
       } catch (FileNotFoundException e) {
           e.printStackTrace();
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           try {
               in.close();
               out.close();
           } catch (IOException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }
    
       }
    }
    

    前端代码:

  • 前端可通过 a 标签的 download 属性实现文件的下载,但是此方式是将请求接口返回的所有数据临时存在浏览器的内存当中,当接口返回所有数据后,才生产文件下载到本地。因此下载大文件时不能使用这种方式。本测试中下载70MB的文件正常,下载2G的文件是文件不能正常打开。可能是因为内存不够导致的文件损坏。

    function sendRequest(event) {
           var responseType = event.data.responseType;
           var inurl = event.data.url;
           console.log(responseType);
    
           var xhr = new XMLHttpRequest();
           var url = $.rootPath + curModule + inurl;
           var method = "GET";
           xhr.open(method, url);
    
           xhr.responseType = responseType;  //responseType 是可读可写属性, 直接通过赋值的方式设置
    
           xhr.send(null);
           xhr.onreadystatechange = function() {
               console.log(xhr.readyState == 4 && xhr.status === 200)
               if (xhr.readyState == 4 && xhr.status === 200) {
                   parseArraybuffer(xhr)
               }
           }
    
       }
    /**
       处理 responseType 为 arraybuffer 的返回结果
       */
       function parseArraybuffer(xhr) {
           var arraybufferType = xhr.getResponseHeader("arraybuffer-type");//后台设置
           console.log(arraybufferType)
           if (arraybufferType == "text") {
               textArraybuffer(xhr.response)
           } else if (arraybufferType == "file") {
               downloadFile(xhr);
           } 
       }
    /**
       使用 a 标签和 Bolb 来实现文件的下载
       */
       function downloadFile(xhr) {
           var fileName = xhr.getResponseHeader("filename");
           var fileType = xhr.getResponseHeader("filetype");
           console.log(xhr);
           //使用a标签实现下载
           var elink = document.createElement('a');
           elink.download = fileName || 'demo.doc';
           elink.style.display = 'none';
           var blob = new Blob([xhr.response]);
           elink.href = URL.createObjectURL(blob);
           document.body.appendChild(elink);
           elink.click();
           document.body.removeChild(elink);
       }
    

    3.responseType 为 blob

    blob的用法与arraybuffer类似,只不过在接收是不用再new Blob对象。不同之处如下:

    function parseBlob(xhr) {
       var fileName = xhr.getResponseHeader("filename");
       var fileType = xhr.getResponseHeader("filetype");
       var elink = document.createElement('a');
       elink.download = fileName || 'demo.doc';
       elink.style.display = 'none';
       var blob = xhr.response;   //返回的是Blob对象,直接接收即可
       elink.href = URL.createObjectURL(blob);
       document.body.appendChild(elink);
       elink.click();
       document.body.removeChild(elink);
    }
    

    4.responseType为json

    responseType为json是目前使用最多的方式,后台返回的数据前端直接作为json对象使用。

    4.1 后台返回List

    当后台返回的数据是List集合时,前端直接解析成为一个数组。可以接使用
    后台代码

    /**
    * responseType 为json,且返回的是一个 List集合
    * @param request
    * @param response
    * @return
    */
    @RequestMapping("json/list")
    public List<String> jsonList(HttpServletRequest request, HttpServletResponse response) {
       ArrayList<String> result = new ArrayList<String>();
       result.add("张三");
       result.add("李四");
       result.add("王五");
       return result;
    }
    

    前端代码

    function parseJson(xhr){
       var resp = xhr.response;
       var type = typeof resp;
       console.log(resp)
       console.log(type)
    }
    

    控制台打印结果:
    image.png

    4.2 后台返回Map

    当后台返回的数据是map集合时,前端直接解析成为一个对象。可以接使用
    后台代码

    /**
    * responseType 为json,且返回的是一个Map集合
    * @param request
    * @param response
    * @return
    */
    @RequestMapping("json/map")
    public Map<String, String> jsonMap(HttpServletRequest request, HttpServletResponse response) {
       Map<String, String> result = new HashMap<String, String>();
       result.put("name", "zhangsan");
       result.put("age", "18");
       result.put("home", "guizhouliupanshui");
       return result;
    }
    

    前端代码

    function parseJson(xhr){
       var resp = xhr.response;
       var type = typeof resp;
       console.log(resp)
       console.log(type)
    }
    

    控制台打印结果
    image.png

    4.3 返回一个实体对象

    后端代码

    /**
    * responseType 为json,且返回的是一个entity
    * @param request
    * @param response
    * @return
    */
    @RequestMapping("json/entity")
    public Person jsonEntity(HttpServletRequest request, HttpServletResponse response) {
       Person p = new Person();
       p.setName("张三");
       p.setAge(18);
    
       Person mom = new Person();
       mom.setName("mother");
       mom.setAge(45);
    
       Person daddy = new Person();
       daddy.setName("father");
       daddy.setAge(45);
    
       Person[] parents = new Person[]{mom, daddy};
       p.setParents(parents);
       return p;
    }
    

    前端代码

    function parseJson(xhr){
       var resp = xhr.response;
       var type = typeof resp;
       console.log(resp)
       console.log(type)
    }
    

    控制台打印结果
    image.png

    4.4 返回一个字符串会怎么样?

    通过以下测试,若将responseType设置为 json,后端返回String是,前端接收到的response将是null, 并且调用responseText时报错。responseText只有 responseType 设置为 “” 或 “text” 时才能访问
    后端代码:

    /**
    * responseType 为json,且返回的是一个字符串
    * @param request
    * @param response
    * @return
    */
    @RequestMapping("json/string")
    public String jsonString(HttpServletRequest request, HttpServletResponse response) {
    
       return "测试一样responseType设置为json,看看返回String会怎样";
    }
    

    前端代码

    function parseJson(xhr){
       var resp = xhr.response;
       var type = typeof resp;
    
       console.log(resp)
    
       console.log(type)
    
       console.log(xhr.responseText)
    }
    

    控制台打印结果
    image.png

5.responseType 为 document

response 是一个 HTML Document 或 XML XMLDocument,这取决于接收到的数据的 MIME 类型。
后端代码:注意 设置content-type 为 application/xml

@RequestMapping("document/xml")
    public void documentString(HttpServletRequest request, HttpServletResponse response) {

        File file = new File("E:\\project\\BackEnd\\xmlhttprequest-demo\\src\\main\\resources\\static\\file\\documentXml.xml");
        InputStream in = null;
        OutputStream out = null;

        String fileName = file.getName();
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        response.setContentType("application/xml");  //设置content-type 为 application/xml
//        response.setHeader("arraybuffer-type", "file");
        response.setHeader("filename", fileName);
        response.setHeader("filetype", fileType);

        //获取要下载的文件输入流
        try {
            in = new FileInputStream(file);
            int len = 0;
            //创建数据缓冲区
            byte[] buffer = new byte[1024];
            //通过response对象获取outputStream流
            out = response.getOutputStream();
            //将FileInputStream流写入到buffer缓冲区
            while((len = in.read(buffer)) > 0) {
                //使用OutputStream将缓冲区的数据输出到浏览器
                out.write(buffer,0,len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

前端代码

function parseDocument(xhr) {
        console.log(xhr.response)
        var domObj = xhr.response;
        if (domObj) {
            var person = {};
            var nameNode = domObj.getElementsByTagName("name");
            var ageNode = domObj.getElementsByTagName("age");
            person.name = nameNode[0].firstChild.nodeValue;
            person.age = ageNode[0].firstChild.nodeValue;
            console.log(person)
        }
    }

控制台打印结果:
image.png