Github - scandipwa/persisted-query
Packagist - scandipwa/persisted-query
scandipwa/persisted-query 是一个用于提升 magento2 graphql 响应速度的库。
大致原理是,把请求的解释缓存在 redis ,把响应的结果缓存在 full page cache (通常是 varnish) 。
只用于 query ,不用于 mutation
persisted-query 依赖
通过 composer 安装
composer require scandipwa/persisted-query:^2.2
修改配置文件 app/etc/env.php ,在 cache中加上这一段
'persisted-query' => [
'redis' => [
'host' => 'localhost',
'scheme' => 'tcp',
'port' => '6379',
'database' => '5'
]
],
修改配置文件 app/etc/config.php
'ScandiPWA_PersistedQuery' => 1,
安装完后记得运行构建命令。大致例子,仅供参考
php bin/magento setup:upgrade && \
php bin/magento setup:di:compile && \
php bin/magento setup:static-content:deploy -f && \
php bin/magento indexer:reindex && \
php bin/magento cache:flush;
大致的使用流程
先发送一次 PUT 请求
https://localhost/graphql?hash=2443957263
PUT 请求成功后会返回 201
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 55
{"error":false,"code":"1","message":"Query registered"}
关键代码的位置 vendor/scandipwa/persisted-query/src/Plugin/PersistedQuery.php
可以通过这个 http 头设置过期时间 SW-cache-age ,这是设置 查询的过期时间
如果没有特别的设置,缓存在刷新时才会失效
bin/magento scandipwa:pq:flush
bin/magento cache:flush persisted_query_response
缓存无效时会返回 401
HTTP/1.1 410 Gone
Content-Type: application/json
Content-Length: 61
{"error":true,"code":"410","message":"Query hash is unknown"}
curl 'https://localhost/graphql?hash=2443957263' \
-X 'PUT' \
-H 'accept: */*' \
-H 'content-type: application/json' \
--data-raw ''
curl -X 'GET' 'https://localhost/graphql?hash=2443957263'
curl 'https://localhost/graphql?hash=2443957282' \
-X 'PUT' \
-H 'accept: */*' \
-H 'content-type: application/json' \
-H 'Cookie: XDEBUG_SESSION=vscode;' \
-d '{
"query": "query GetProductsBySkus($_filter:ProductAttributeFilterInput!, $_pageSize:Int) { products(search: \"*\", filter: $_filter, pageSize: $_pageSize ) { items { id uid sku name image { url } url_key url_suffix stock_status categories { uid name } } } }"
}'
curl -X 'GET' 'https://localhost/graphql?hash=2443957282&_filter=%257B%2522sku%2522%253A%257B%2522in%2522%253A%255B%2522sku1%2522%252C%2522sku2%2522%252C%2522sku3%2522%255D%257D%257D&_pageSize=1'
假设这是原本的请求
curl 'https://localhost/graphql' \
-X 'POST' \
-H 'accept: */*' \
-H 'content-type: application/json' \
-H 'Cookie: XDEBUG_SESSION=vscode;' \
-d '{
"query": "query GetProductsBySkus($_filter:ProductAttributeFilterInput!, $_pageSize:Int) { products(search: \"*\", filter: $_filter, pageSize: $_pageSize ) { items { id uid sku name image { url } url_key url_suffix stock_status categories { uid name } } } }",
"variables":{"_filter":{"sku":{"in":["sku1","sku2","sku3"],"_pageSize":1}}}
}'
variablesPUTcurl 'https://localhost/graphql?hash=2443957282' \
-X 'PUT' \
-H 'accept: */*' \
-H 'content-type: application/json' \
-H 'Cookie: XDEBUG_SESSION=vscode;' \
-d '{
"query": "query GetProductsBySkus($_filter:ProductAttributeFilterInput!, $_pageSize:Int) { products(search: \"*\", filter: $_filter, pageSize: $_pageSize ) { items { id uid sku name image { url } url_key url_suffix stock_status categories { uid name } } } }",
}'
后续的请求中,把 variables 转换为 url编码,再直接加在 url 里
curl -X 'GET' 'https://localhost/graphql?hash=2443957282&_filter=%257B%2522sku%2522%253A%257B%2522in%2522%253A%255B%2522sku1%2522%252C%2522sku2%2522%252C%2522sku3%2522%255D%257D%257D&_pageSize=1'
这是把 variables 转换为 url编码 的伪代码
$variables = '{"_filter":{"sku":{"in":["sku1","sku2","sku3"]}},"_pageSize":1}';
$variables = json_decode($variables, true);
foreach ($variables as $key => $value) {
$variables[$key] = urlencode(json_encode($value));
}
echo http_build_query($variables);
<!--
php -a <<- 'EOF'
$variables='{"_filter":{"sku":{"in":["sku1","sku2","sku3"]}},"_pageSize":1}';
echo http_build_query(array_map(fn($value) => urlencode(json_encode($value)), json_decode($variables, true)));
EOF
node <<- 'EOF'
const variables = '{"_filter":{"sku":{"in":["sku1","sku2","sku3"]}},"_pageSize":1}';
console.log(Object.entries(JSON.parse(variables)).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(value))}`).join('&'));
EOF
echo '{"_filter":{"sku":{"in":["sku1","sku2","sku3"]}},"_pageSize":1}' | \
python -c "import sys;import json;import urllib.parse;variables=sys.stdin.read();
print('&'.join(f'{urllib.parse.quote(key)}={urllib.parse.quote(json.dumps(value, separators=(',', ':')))}' for key, value in json.loads(variables).items()))"
-->