如何创建 Google Chrome UX API 批量查询?

How to create a Google Chrome UX API batch query?

我尝试了 documentation page 中的示例,但出现错误(例如 invalid url,这实际上是有效的)让我无法理解我做错了什么。

有人可以给我一个 cURL 风格的批量查询示例吗?

试过: 我试过以下方法:

但是,结果我没有得到这样的响应,如文档中所述,而是状态 404 和我查询的第一个网站的源代码 - 我的请求和响应 header 您可以在截图:

以下是使用 cURL 进行批量请求的示例:

curl -d '

--Batch

POST /v1/records:queryRecord?key=YOUR_API_KEY HTTP/1.1
Content-ID: item1
Content-Type: application/json

{"origin":"https://example.com", "metrics": ["first_contentful_paint"]}

--Batch

POST /v1/records:queryRecord?key=YOUR_API_KEY HTTP/1.1
Content-ID: item2
Content-Type: application/json

{"url":"https://example.com/", "metrics": ["first_contentful_paint"]}

--Batch--
' -H 'Content-Type: multipart/mixed; boundary="Batch"' -X POST -s https://chromeuxreport.googleapis.com/batch/ -v

响应如下所示:

--batch_R4dQQd20Vo_-lf91w1QTFvMinqZc7Zyj
Content-Type: application/http
Content-ID: response-item1

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Vary: Origin
Vary: X-Origin
Vary: Referer

{
  "record": {
    "key": {
      "origin": "https://example.com"
    },
    "metrics": {
      "first_contentful_paint": {
        "histogram": [
          {
            "start": 0,
            "end": 1000,
            "density": 0.53746873436718867
          },
          {
            "start": 1000,
            "end": 3000,
            "density": 0.39049524762381554
          },
          {
            "start": 3000,
            "density": 0.072036018009005318
          }
        ],
        "percentiles": {
          "p75": 1748
        }
      }
    }
  }
}

--batch_R4dQQd20Vo_-lf91w1QTFvMinqZc7Zyj
Content-Type: application/http
Content-ID: response-item2

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Vary: Origin
Vary: X-Origin
Vary: Referer

{
  "record": {
    "key": {
      "url": "https://example.com/"
    },
    "metrics": {
      "first_contentful_paint": {
        "histogram": [
          {
            "start": 0,
            "end": 1000,
            "density": 0.5311186712027276
          },
          {
            "start": 1000,
            "end": 3000,
            "density": 0.39493696217731078
          },
          {
            "start": 3000,
            "density": 0.073944366619972793
          }
        ],
        "percentiles": {
          "p75": 1768
        }
      }
    }
  }
}

--batch_R4dQQd20Vo_-lf91w1QTFvMinqZc7Zyj--

编辑:我在 CrUXApiUtil 中添加了一个方法来为您处理 JS 应用程序中的所有批处理物流。

CrUXApiUtil.batch = function (requests) {
  if (CrUXApiUtil.API_KEY == '[YOUR_API_KEY]') {
    throw 'Replace "YOUR_API_KEY" with your private CrUX API key. Get a key at https://goo.gle/crux-api-key.';
  }

  const BOUNDARY = 'BATCH_BOUNDARY';
  return fetch(CrUXApiUtil.API_BATCH_ENDPOINT, {
    method: 'POST',
    headers: {
      'Content-Type': `multipart/mixed; boundary="${BOUNDARY}"`
    },
    body: `--${BOUNDARY}\n` + requests.map((requestBody, i) => {
      return `
POST ${CrUXApiUtil.API_ENDPOINT_PATH} HTTP/1.1
Content-ID: crux-${i}
Content-Type: application/json

${JSON.stringify(requestBody)}`;
    }).join(`\n\n--${BOUNDARY}\n`) + `\n\n--${BOUNDARY}--`
  }).then(response => {
    const contentTypeHeader = response.headers.get('Content-Type');
    const boundaryPattern = /\bboundary=([\w-]+)\b/i;
    if (!boundaryPattern.test(contentTypeHeader)) {
      throw `Unable to parse boundary directive from Content-Type response header: "${contentTypeHeader}"`;
    }

    const boundary = contentTypeHeader.match(boundaryPattern)[1];
    return Promise.all([
      Promise.resolve(boundary),
      response.text()
    ]);
  }).then(([boundary, response]) => {
    const responseParts = response.split(`--${boundary}`);
    // Eject boundary bookends
    responseParts.shift();
    responseParts.pop();

    const responseJSONPattern = /\n({[\s\S]*)/m;
    return responseParts.map(part => {
      if (!responseJSONPattern.test(part)) {
        console.error(`Unable to parse CrUX API response from:\n${response}`);
        return null;
      }
      return JSON.parse(part.match(responseJSONPattern)[1]);
    });
  });
}

示例输入:

CrUXApiUtil.batch([
  {"origin":"https://example.com", "metrics": ["first_contentful_paint"]},
  {"url":"https://example.com/", "metrics": ["first_contentful_paint"]}
]).then(console.log)

示例输出:

[
  {
    "record": {
      "key": {
        "origin": "https://example.com"
      },
      "metrics": {
        "first_contentful_paint": {
          "histogram": [
            {
              "start": 0,
              "end": 1000,
              "density": 0.5374687343671887
            },
            {
              "start": 1000,
              "end": 3000,
              "density": 0.39049524762381554
            },
            {
              "start": 3000,
              "density": 0.07203601800900532
            }
          ],
          "percentiles": {
            "p75": 1748
          }
        }
      }
    }
  },
  {
    "record": {
      "key": {
        "url": "https://example.com/"
      },
      "metrics": {
        "first_contentful_paint": {
          "histogram": [
            {
              "start": 0,
              "end": 1000,
              "density": 0.5311186712027276
            },
            {
              "start": 1000,
              "end": 3000,
              "density": 0.3949369621773108
            },
            {
              "start": 3000,
              "density": 0.07394436661997279
            }
          ],
          "percentiles": {
            "p75": 1768
          }
        }
      }
    }
  }
]

crux-api 有助于生成批处理请求,自动支持重试(CrUX API 配额按记录计算)和空记录。这是一个支持 TS 的小型(500 字节)同构库。

import { createBatch } from 'crux-api/batch'
const batch = createBatch({ key: CRUX_API_KEY })

const records = await batch([
  { url: 'https://github.com/', formFactor: 'MOBILE', effectiveConnectionType: '4G' },
  { url: 'https://github.com/marketplace', formFactor: 'DESKTOP' },
  { url: 'https://www.github.com/explore', formFactor: 'TABLET' },
  // ... up to 1000 records.
])