操作签名
了解 GraphOS 如何识别等效操作
当您查看您的图's 操作指标,GraphOS Studio组操作基于它们包含的字段集,而不是基于操作名称。这意味着具有相同名称但不同字段集的操作将分别显示:
尽管上述示例中的每个操作都被称为MyQuery
,GraphOS将它们视为不同的操作,因为它们请求不同的字段。
为了帮助GraphOS识别功能上相同的操作,您的路由器为每个报告给 Studio 的operation signature生成一个操作签名。这是一个具有确定性的字段顺序、空白和行内参数值的标准化表示。
为什么我们需要操作签名?
考虑到以下操作:
query GetPostDetails($postId: String!) {post(id: $postId) {authorcontent}}query GetPostDetails($postId: String!) {post(id: $postId) {content # Different field orderauthor}}query GetPostDetails($postId: String!) {post(id: $postId) {writer: author # Field aliascontent}}
尽管有些外观上的差异(包括注释),但这些操作在特定GraphQL服务器上执行方式相同。因此,Studio 应该在显示性能指标时将它们分组。
尽管有些外观上的差异(包括注释),但这些操作在特定GraphQL服务器上执行方式相同。因此,Studio 应该在显示性能指标时将它们分组。签名算法
签名算法
ⓘ 注意
此签名算法可能会有所更改。这里提供它是为了信息目的,而不是作为一个规范性规范。
签名算法对一个操作执行以下修改以生成其签名:
- 转换行内参数的值。
- 移除多余的字符。
- 重新排序定义。
1. 转换行内参数值
如果一个操作包含任何行内参数的值,算法会根据它们的类型来转换这些值:
布尔值
和枚举值
被保留。整数
和浮点数
值被替换为0
。字符串
、列表和对象值被替换为其“空”对应物(""
、[]
或{}
)。
参数值作为GraphQL 变量名称被保留。
ⓘ 注意
使用GraphOS 路由器的组织可以启用增强的操作签名生成。增强的操作签名包括输入对象形状,同时仍然隐藏实际值。有关更多信息,请查看路由器配置页面。
2. 移除多余的字符
算法移除了操作定义中的大多数不必要字符,包括注释和多余的空白。
如果一个操作文档包含多个操作,那么除了执行操作之外的操作都会被移除。
如果一个操作文档包含未由执行操作使用的片段,则这些片段将被移除(保留其他片段)。
3. 重新排序定义
任何保留的片段定义首先出现,按片段名称进行字母数字排序。执行操作的定义随后出现在所有片段定义之后。
ⓘ 注意
如果有两个排序项的名称相同,算法将保留这些项相对于彼此的原始顺序。
字段
对于给定的对象或片段的字段,字段选择按以下顺序排序:
- 单独列出的字段
- 命名片段扩展
- 内联片段
在这些之中,根据字段名称或片段名称进行字母数字排序。
字段别名
删除所有字段别名。如果一个操作包含相同字段的不同别名的三个实例,则该字段以非别名的名称在签名中列出三次。
ⓘ 注意
使用GraphOS Router的组织可以启用不删除字段别名的增强操作签名生成。有关更多信息,请参阅路由器配置页面。
指令和参数
如果在操作文档的同一位置应用了多个指令,则这些指令按字母顺序排序。
如果一个字段接受多个参数,则这些参数按名称进行字母数字排序。
示例签名
考虑这个操作:
# Operation definition needs to appear after all fragment definitionsquery GetUser {user(id: "hello") {# Replace string argument value with empty string...NameParts # Spread fragment needs to appear after individual fieldstimezone # Needs to appear alphanumerically after `name`aliased: name # Need to remove alias}}# Excessive characters (including this comment!) need to be removedfragment NameParts on User {firstnamelastname}
签名算法为这个操作生成以下签名:
fragment NameParts on User {firstnamelastname}query GetUser {user(id: "") {nametimezone...NameParts}}
签名和敏感数据
签名算法的主要目的是将仅从外观上(如空格、字段顺序、别名等)有所不同的操作分组。作为额外的效果,算法会删除大部分内联参数值,理论上有助于保护数据隐私。
然而,你不应该依赖于这一点。理想情况下,你的敏感数据永远不会首先到达GraphOS Studio。尽可能使用GraphQL变量,而不是内联值作为参数,这有助于你精确控制向Apollo报告哪些值。有关详细信息,请参阅GraphOS Studio数据隐私和合规性。
运行时记录签名
GraphOS Router
自 Apollo 路由核心 v1.43.1,路由器在 apollo_operation_signature
关键字处添加 操作签名 以请求上下文。您还可以使用路由器的本地日志功能将上下文值作为 跟踪属性 录入,或者您可以通过 Rhai 脚本 或 协处理器 读取上下文。
自
Apollo 服务器
要查看您自己日志工具中的操作签名哈希值,您可以创建一个 Apollo 服务器插件,该插件可从共享的 语境
中获取哈希值。相关的值在 queryHash
和 operationName
属性中可用:
const logOperationSignaturePlugin = {async requestDidStart() {return {async didResolveOperation(ctx) {console.log({queryHash: ctx.queryHash,operationName: ctx.operationName,});},};},};const server = new ApolloServer({schema,plugins: [logOperationSignaturePlugin],});
const logOperationSignaturePlugin = {async requestDidStart() {return {async didResolveOperation(ctx) {console.log({queryHash: ctx.queryHash,operationName: ctx.operationName,});},};},};const server = new ApolloServer({schema,plugins: [logOperationSignaturePlugin],});