【问题标题】:Javascript - How to know the type of the response in Fetch API?Javascript - 如何知道 Fetch API 中的响应类型?
【发布时间】:2018-06-07 22:39:19
【问题描述】:

如何知道 Fetch API 的响应类型?

在 XMLHttpRequest 中,responseType property 指示返回的响应正文的类型(json、文本、blob 等)。虽然在Fetch API response 中,尽管有一些有用的方法可以解析它的主体(json()text()blob() 等),但我仍然没有找到像 XMLHttpRequest 的responseType 属性这样的属性,指示响应的类型。

【问题讨论】:

    标签: javascript xmlhttprequest fetch-api


    【解决方案1】:

    我认为 orangespark 是对的。应该使用content-type 响应标头

    1. 如果content-type 标头丢失或无效。可以进一步处理响应:

      提取 MIME 类型返回失败 或对于给定格式本质不正确 的 MIME 类型时,将其视为致命错误。现有的网络平台功能并不总是遵循这种模式,多年来,这一直是这些功能中安全漏洞的主要来源。相反,通常可以安全地忽略 MIME 类型的参数。 https://fetch.spec.whatwg.org/#content-type-header

    2. 由于有许多有效的媒体类型,一些库惰性探测Content-Type 标头:response.headers.get("content-type").includes('json') 表示json 存在,在调用response.json() 之前。

      有 1500+ 个Media types 注册了IANA,可以将其设置为请求的 Content-Type。

    3. 如果content-type 未设置(或忘记设置)。 defaulttext/plain 可能由服务器设置,这会“破坏”您的响应处理。

    4. 如果content-type 不是可接受的媒体类型之一,或者bodycontent-type 不匹配...

      请求:

      接受:text/html, image/avif;q=0.9, image/apng;q=0.8

      反应(坏):

      内容类型:应用程序/json

      ...在阅读body 之前,您可以使您的应用程序更安全,clone()response。所以你仍然可以返回 JSON,例如text 响应出现错误,无法解析为 JSON。

      const response2 = response.clone();
      let data;
      try {
          data = await response.json(); // SyntaxError: Unexpected token in JSON
      } catch (e) {
          text = await response2.text(); // response clone can still read as a fallback
          data = {
              error: e.message,
              invalidJson: text
          };
      }
      
    5. 您可以使用response.blob() 作为response.text()response.json()、...的替代品...

      返回的Blob 有一个属性blob.type,其中包含content-type 标头值。

      这里有一些示例,如何处理这些 blob:

      1. Blob SVG:image/svg+xml 内容
      2. Blob HTML:text/html 内容
      3. Blob JSON application/json 内容
      4. Blob JSON application/octet-stream 内容
      5. Blob 错误 ???/??? 内容

    (async() => {
      const c = document.body;
    
      imageBlob = () => {
        const svg = `<svg viewBox="0 0 200 200" width="80" height="80" xmlns="http://www.w3.org/2000/svg"><path fill="#FF0066" d="M31.5,-16.8C35.9,3.2,31,19.6,16.3,32.8C1.5,46,-23.2,55.9,-36.6,46.9C-50.1,38,-52.3,10.1,-44.3,-14.8C-36.4,-39.8,-18.2,-61.9,-2.3,-61.2C13.6,-60.4,27.2,-36.8,31.5,-16.8Z" transform="translate(100 100)" /></svg>`;
        return new Blob(
          [svg], {
            type: 'image/svg+xml'
          }
        );
      }
    
      htmlBlob = () => {
        return new Blob(
          ['<span>HTML <b style="color: red">blob</b></span>'], {
            type: 'text/html'
          }
        );
      }
    
      jsonBlob = type => {
        const json = {
          a: 1,
          b: {
            c: 'val'
          }
        }
        const jsonStr = JSON.stringify(json);
        return new Blob([jsonStr], {
          type
        });
      }
    
      // Blob instances you might get from: await response.blob()
      // blob.type is set from 'Content-Type' header of its response
      const blobs = [
        imageBlob(),                          // 1
        htmlBlob(),                           // 2
        jsonBlob('application/json'),         // 3
        jsonBlob('application/octet-stream'), // 4
        jsonBlob('???/???')                   // 5
      ]
    
      for (const [i, b] of Object.entries(blobs)) {
        c.append(Object.assign(document.createElement('h3'), {
          textContent: `${1+parseInt(i)}. ${b.type}:`
        })) //      b.type === 'Content-Type'━━┛
    
        if (b.type.startsWith('text/html')) { // 1
          const text = await b.text();
          c.append(Object.assign(document.createElement('div'), {
            innerHTML: text
          }));
        } else if (b.type.startsWith('image/')) { // 2
          c.append(Object.assign(document.createElement('img'), {
            src: URL.createObjectURL(b)
          }));
        } else if (b.type.startsWith('application/json')) { // 3
          c.append(Object.assign(document.createElement('pre'), {
            textContent: JSON.stringify(JSON.parse(await b.text()), null, ' ')
          }));
        } else if (b.type.startsWith('application/octet-stream')) { // 4
          c.append(Object.assign(document.createElement('a'), {
            textContent: 'download json',
            href: URL.createObjectURL(b),
            download: 'data.json'
          }));
        } else { // 5
            // .... create a clone Response from blob
            // -> response2 = new Response(await response1.blob())
            const response2 = new Response(b);
            const b2 = await response2.blob(); // .json() .text(),...
            const text2 = await b2.text(); 
            console.log('blob2', text2, b2.type);
    
            // Blogs are  b === b2
            const text = await b.text();
            console.log('blob1', text, b.type);
            
            console.log('blob2 === blob1', text === text2); // true
        }
      }
      
          c.append(Object.assign(document.createElement('h3'), {
          innerHTML: `&nbsp;<br>&nbsp;`
        }))
    })()

    【讨论】:

      【解决方案2】:

      我认为您可以检查内容类型的响应标头,如下所示:

      response.headers.get("content-type")
      

      【讨论】:

        猜你喜欢
        • 2019-09-21
        • 2019-09-02
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-21
        • 2019-07-25
        • 1970-01-01
        相关资源
        最近更新 更多