如何创建 Google Chrome UX API 批量查询?
How to create a Google Chrome UX API batch query?
我尝试了 documentation page 中的示例,但出现错误(例如 invalid url
,这实际上是有效的)让我无法理解我做错了什么。
有人可以给我一个 cURL 风格的批量查询示例吗?
试过: 我试过以下方法:
- 将文档页面中的示例复制到在线 cURL 工具中,
- 在开始前添加
curl --request
POST
,
- 添加了我的 API 密钥,
- 将域添加到它们应该在的地方。
但是,结果我没有得到这样的响应,如文档中所述,而是状态 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.
])
我尝试了 documentation page 中的示例,但出现错误(例如 invalid url
,这实际上是有效的)让我无法理解我做错了什么。
有人可以给我一个 cURL 风格的批量查询示例吗?
试过: 我试过以下方法:
- 将文档页面中的示例复制到在线 cURL 工具中,
- 在开始前添加
curl --request
POST
, - 添加了我的 API 密钥,
- 将域添加到它们应该在的地方。
但是,结果我没有得到这样的响应,如文档中所述,而是状态 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.
])