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

Javascript - How to know the type of the response in Fetch API?

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

在 XMLHttpRequest 中,有 responseType property which indicates the type of the returned response's body (json, text, blob, etc.). While in the Fetch API response,即使有有用的方法来解析它的主体(json()text()blob() 等),我仍然没有找到任何 属性 像 XMLHttpRequest 的 responseType 属性 来指示响应的类型。

我认为您可以检查 content-type 响应的 headers,如下所示:

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

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

  1. 如果 content-type header 缺失或无效。 top 进一步处理响应即可:

    When extract a MIME type returns failure or a MIME type whose essence is incorrect for a given format, treat this as a fatal error. Existing web platform features have not always followed this pattern, which has been a major source of security vulnerabilities in those features over the years. In contrast, a MIME type’s parameters can typically be safely ignored. https://fetch.spec.whatwg.org/#content-type-header

  2. 由于有许多有效的媒体类型,一些库 lazy probe Content-Type header: response.headers.get("content-type").includes('json') for json 存在,在 response.json() 被调用之前。

    There are 1500+ Media types registered with the IANA which can be set as the Content-Type for a request.

  3. 如果content-type没有设置(或忘记设置)。 text/plaindefault 可能由服务器设置,这将 'break' 您的响应处理。

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

    要求:

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

    响应(差):

    content-type: application/json

    ...您可以在阅读 body 之前让您的应用程序更加故障安全并 clone() response。所以你仍然可以 return JSON 例如无法解析为 JSON.

    text 响应错误
    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()、...

    的替代方案

    returned Blob 有一个 属性 blob.type 保存 content-type header 值。

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

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