Apollo GraphQL

news2024/12/19 16:58:46

一、Apollo GraphQL介绍

Apollo 是一个开源的 GraphQL 开发平台, 提供了符合 GraphQL 规范的服务端和客户端实现。使用 Apollo 可以帮助我们更方便快捷的开发使用 GraphQL。

在这里插入图片描述
● 官网:https://www.apollographql.com/
● GitHub 相关开源仓库:https://github.com/apollographql

二、基本用法

1、准备

# 创建项目目录
mkdir graphql-server-example
cd graphql-server-example

# 初始化 package.json 文件
npm init -y

# 安装依赖
npm install apollo-server graphql

# 创建 index.js
touch index.js

2、index.js

const { ApolloServer, gql } = require('apollo-server')

const typeDefs = gql`
  # Comments in GraphQL strings (such as this one) start with the hash (#) symbol.

  # This "Book" type defines the queryable fields for every book in our data source.
  type Book {
    title: String
    author: String
  }

  # The "Query" type is special: it lists all of the available queries that
  # clients can execute, along with the return type for each. In this
  # case, the "books" query returns an array of zero or more Books (defined above).
  type Query {
    books: [Book]
  }
`

const books = [
  {
    title: 'The Awakening',
    author: 'Kate Chopin'
  },
  {
    title: 'City of Glass',
    author: 'Paul Auster'
  }
]

const resolvers = {
  Query: {
    books: () => books
  }
}

// The ApolloServer constructor requires two parameters: your schema
// definition and your set of resolvers.
const server = new ApolloServer({ typeDefs, resolvers })

// The `listen` method launches a web server.
server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`)
})

关于 gql 标签模板

  • gql 标签模板将查询字符串解析为 AST,用于使用 Prettier 突出显示编辑器语法和自动格式化。
  • 将来,我们将使用它来静态分析 GraphQL 查询,因此 Apollo Server 需要使用 gql 包装您的 schema。
  • gql 也可以用作将字符串转换为AST的常规函数

三、与 Node.js 中间件集成

Apollo Server 可以轻松地与几个流行的 Node.js 中间件库集成。要集成,请首先从下表中安装适当的软件包,而不是核心 apollo-server 软件包。

兼容的软件包

MIDDLEWAREPACKAGE
Expressapollo-server-express
AWS Lambdaapollo-server-lambda
Koaapollo-server-koa
hapiapollo-server-hapi
Microapollo-server-micro
Fastifyapollo-server-fastify
Google Cloud Functionsapollo-server-cloud-functions
Azure Functionsapollo-server-azure-functions
Cloudflareapollo-server-cloudflare

如果您已经安装了核心 apollo-server 软件包,则可以在安装集成软件包后 npm 卸载它。

应用中间件

与中间件集成时,首先像往常一样初始化 Apollo Server,然后调用 applyMiddleware。

这是为 Hello 服务的基本 Express 示例。从 /graphql 以外的每个路径访问,该路径与 Apollo Server 一起提供GraphQL端点:

const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const { typeDefs, resolvers } = require('./schema');

const app = express();
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.applyMiddleware({ app });

app.use((req, res) => {
  res.status(200);
  res.send('Hello!');
  res.end();
});

app.listen({ port: 4000 }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
)

您提供给 applyMiddleware 的参数是中间件对应用程序的顶级表示。在 Express 应用程序中,此变量通常称为app。

当您将应用程序传递给 applyMiddleware 时,Apollo Server 会自动配置各种中间件(包括请求体解析,GraphQL Playground 前端和 CORS 支持),因此您不需要通过诸如 app.use 之类的机制来应用它们。

四、解析器

基本用法
schema:

type Query {
  numberSix: Int! # Should always return the number 6 when queried
  numberSeven: Int! # Should always return 7
}

resolver:

const resolvers = {
  Query: {
    numberSix() {
      return 6;
    },
    numberSeven() {
      return 7;
    }
  }
};

处理参数

schema:

type User {
  id: ID!
  name: String
}

type Query {
  user(id: ID!): User
}

resolver:

const users = [
  {
    id: '1',
    name: 'Elizabeth Bennet'
  },
  {
    id: '2',
    name: 'Fitzwilliam Darcy'
  }
];

const resolvers = {
  Query: {
    user(parent, args, context, info) {
      return users.find(user => user.id === args.id);
    }
  }
}

解析器链

schema:

# A library has a branch and books
type Library {
  branch: String!
  books: [Book!]
}

# A book has a title and author
type Book {
  title: String!
  author: Author!
}

# An author has a name
type Author {
  name: String!
}

type Query {
  libraries: [Library]
}

有效的查询语法:

query GetBooksByLibrary {
  libraries {
    books {
      author {
        name
      }
    }
  }
}

此查询的结果解析器链与查询本身的层次结构匹配:

在这里插入图片描述
这些解析器按上述顺序执行,并将其返回值通过父参数传递给链中的下一个解析器。
resolver 处理如下:

const { ApolloServer, gql } = require('apollo-server');

const libraries = [
  {
    branch: 'downtown'
  },
  {
    branch: 'riverside'
  },
];

// The branch field of a book indicates which library has it in stock
const books = [
  {
    title: 'The Awakening',
    author: 'Kate Chopin',
    branch: 'riverside'
  },
  {
    title: 'City of Glass',
    author: 'Paul Auster',
    branch: 'downtown'
  },
];

// Schema definition
const typeDefs = gql`

# A library has a branch and books
  type Library {
    branch: String!
    books: [Book!]
  }

  # A book has a title and author
  type Book {
    title: String!
    author: Author!
  }

  # An author has a name
  type Author {
    name: String!
  }

  # Queries can fetch a list of libraries
  type Query {
    libraries: [Library]
  }
`;

// Resolver map
const resolvers = {
  Query: {
    libraries() {

      // Return our hardcoded array of libraries
      return libraries;
    }
  },
  Library: {
    books(parent) {

      // Filter the hardcoded array of books to only include
      // books that are located at the correct branch
      return books.filter(book => book.branch === parent.branch);
    }
  },
  Book: {

    // The parent resolver (Library.books) returns an object with the
    // author's name in the "author" field. Return a JSON object containing
    // the name, because this field expects an object.
    author(parent) {
      return {
        name: parent.author
      };
    }
  }

  // Because Book.author returns an object with a "name" field,
  // Apollo Server's default resolver for Author.name will work.
  // We don't need to define one.
};

// Pass schema definition and resolvers to the
// ApolloServer constructor
const server = new ApolloServer({ typeDefs, resolvers });

// Launch the server
server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});

如果现在我们更新查询以同时询问每本书的标题:

query GetBooksByLibrary {
  libraries {
    books {

      title
      author {
        name
      }
    }
  }
}

然后,解析器链如下所示:

在这里插入图片描述
当一条链像这样“发散”时,每个子链并行执行。

解析器参数

解析程序函数按顺序接受以下位置参数:

ARGUMENTDESCRIPTION
parent此字段的父项(即,解析程序链中的前一个解析程序)的解析程序的返回值。对于没有父级的顶级字段的解析器(例如Query的字段),此值是从传递给Apollo Server构造函数的rootValue函数获得的。
args包含为此字段提供的所有GraphQL参数的对象。例如,当执行查询 { user(id: “4”) } 时,传递给用户解析器的args对象是 { “id”: “4” }。
context在为特定操作而执行的所有解析器之间共享的对象。使用它可以共享每个操作的状态,包括身份验证信息,数据加载器实例以及在解析器之间进行跟踪的其他任何内容。
info包含有关操作执行状态的信息,包括字段名称,从根到字段的路径等。GraphQL.js源代码中列出了它的核心字段,并且其他模块(例如apollo-cache-control)通过附加功能对其进行了扩展。

context 参数

context 参数对于传递任何解析器可能需要的东西很有用,例如身份验证范围,数据库连接和自定义获取函数。如果您正在使用数据加载器跨解析器批处理请求,则也可以将它们附加到上下文。

解析器决不应破坏性地修改上下文参数。这样可以确保所有解析程序的一致性,并防止意外错误。

要为您的解析器提供上下文,请向 ApolloServer 构造函数添加上下文初始化函数。每个请求都会调用此函数,因此您可以根据请求的详细信息(例如HTTP标头)设置上下文。


// Constructor
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: (req) => ({
    authScope: getScope(req.headers.authorization)
  })
}));

// Example resolver
(parent, args, context, info) => {
  if(context.authScope !== ADMIN) throw new AuthenticationError('not admin');
  // Proceed
}

如果您使用的是 Express 以外的中间件,则传递给上下文函数的对象的字段会有所不同。有关详细信息,请参见API参考。

上下文初始化可以是异步的,从而可以完成数据库连接和其他操作:

context: async () => ({
  db: await client.connect(),
})

// Resolver
(parent, args, context, info) => {
  return context.db.query('SELECT * FROM table_name');
}

返回值

Apollo Server根据其类型对解析器函数的返回值进行不同的处理:

类型详情
Scalar / object解析程序可以返回单个值或对象,如定义解析程序中所示。该返回值通过父参数传递给任何嵌套的解析器。
Array当且仅当您的模式指示解析器的关联字段包含列表时,才返回一个数组。
返回数组后,Apollo Server为数组中的每个项目执行嵌套的解析器。
null / undefined表示找不到该字段的值。如果您的模式指示此解析器的字段可为空,则操作结果在该字段的位置具有空值。如果此解析器的字段不可为空,则Apollo Server会将字段的父级设置为null。如有必要,此过程将继续沿解析程序链向上移动,直至到达可为空的字段。这样可以确保响应永远不会为不可为空的字段包含空值。
Promise解析程序通常执行异步操作,例如从数据库或后端API提取。为了支持这一点,解析器可以返回可解析为其他任何受支持的返回类型的promise。

默认解析器

如果您没有为特定的架构字段定义解析器,则Apollo Server会为其定义默认解析器(请参阅源代码)。

默认的解析器功能使用以下逻辑:

在这里插入图片描述
例如,请考虑以下 schema:

type Book {
  title: String
}

type Author {
  books: [Book]
}

如果 books 字段的解析程序返回一个对象数组,每个对象包含一个 title 字段,则可以为 title 字段使用默认的解析程序。默认解析器将正确返回 parent.title。

监控解析器性能

与所有代码一样,解析器的性能取决于其逻辑。重要的是要了解模式中的哪些字段在计算上是昂贵的或难以解决的,以便您可以提高其性能或确保仅在必要时查询它们。

Apollo Studio 直接与 Apollo Server 集成在一起,以提供字段级指标,以帮助您了解一段时间内数据图的性能。有关更多信息,请参阅分析性能。

在本地进行开发时,您可以为 ApolloServer 构造函数提供 tracing: true,以启用跟踪面板:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  tracing: true,
});

五、连接到数据源

Apollo Server 可以从多给位置获取数据。

Apollo提供了一个 DataSource 类,我们可以扩展该类以处理特定类型的数据源的交互逻辑。

连接到 REST API

连接到数据库

● SQLDataSource from datasource-sql
● MongoDataSource from apollo-datasource-mongodb

从解析器访问数据

为了使解析器能够访问数据源,可以将它们作为选项传递给 ApolloServer 构造函数:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  dataSources: () => {
    return {
      moviesAPI: new MoviesAPI(),
      personalizationAPI: new PersonalizationAPI(),
    };
  },
  context: () => {
    return {
      token: 'foo',
    };
  },
});

Apollo Server 会将每个请求的数据源放在上下文中,因此您可以从解析器访问它们。它还将使您的数据源可以访问上下文。 (之所以没有让用户直接将数据源放在上下文中,是因为这会导致循环依赖。)
从解析器中,我们可以访问数据源并返回结果:

 Query: {
    movie: async (_source, { id }, { dataSources }) => {
      return dataSources.moviesAPI.getMovie(id);
    },
    mostViewedMovies: async (_source, _args, { dataSources }) => {
      return dataSources.moviesAPI.getMostViewedMovies();
    },
    favorites: async (_source, _args, { dataSources }) => {
      return dataSources.personalizationAPI.getFavorites();
    },
  },

关于 DataLoader
使用 Memcached/Redis 缓存后端数据
实现自己的缓存后端

六、错误处理

Apollo 服务器提供了一组预定义的错误,包括 AuthenticationError,ForbiddenError,UserInputError 和常规 ApolloError。这些错误旨在增强 GraphQL 执行之前和执行过程中引发的错误,从而使调试 Apollo Server 集成更加容易,并使客户端能够基于错误采取特定的措施。
当解析器内部和外部的 Apollo Server 中都发生错误时,errors 数组内部的每个错误都包含一个扩展对象,该对象包含由 Apollo Server 添加的信息。

默认信息

改善服务器可用性的第一步是默认情况下提供错误堆栈跟踪。下面的示例演示了从Apollo Server返回的响应,该响应带有引发节点 SystemError 的解析器。

const {
  ApolloServer,
  gql,
} = require('apollo-server');

const typeDefs = gql`
  type Query {
    readError: String
  }
`;

const resolvers = {
  Query: {

    readError: (parent, args, context) => {
      fs.readFileSync('/does/not/exist');
    },
  },
};

响应结果如下:

在这里插入图片描述
要为生产禁用堆栈跟踪,请将 debug: false 传递给 Apollo Server 构造函数,或者将 NODE_ENV 环境变量设置为 ‘production’ 或 ‘test’。请注意,这会使 stacktrace 对您的应用程序不可用。如果要记录堆栈跟踪信息,但不将其发送给客户端,请参阅下面的屏蔽和记录错误。

错误代号

除了堆栈跟踪外,Apollo Server 导出的错误还在扩展的代码字段中指定了人类可读的字符串,该字符串使客户端能够执行纠正措施。除了改善客户体验之外,代码字段还允许服务器对错误进行分类。例如,AuthenticationError 将代码设置为 UNAUTHENTICATED,这使客户端可以重新进行身份验证,通常会被视为服务器异常而被忽略。

const {
  ApolloServer,
  gql,

  AuthenticationError,
} = require('apollo-server');

const typeDefs = gql`
  type Query {
    authenticationError: String
  }
`;

const resolvers = {
  Query: {

    authenticationError: (parent, args, context) => {
      throw new AuthenticationError('must authenticate');
    },
  },
};

响应结果如下:
在这里插入图片描述

扩大错误的详细信息

当客户端提供错误的输入时,您可能希望针对无效的每个字段或参数返回其他信息,例如本地化消息。下面的示例演示如何使用 UserInputError 来添加更多详细信息来增加错误消息。

const {
  ApolloServer,
  UserInputError,
  gql,
} = require('apollo-server');

const typeDefs = gql`
  type Mutation {
    userInputError(input: String): String
  }
`;

const resolvers = {
  Mutation: {

    userInputError: (parent, args, context, info) => {
      if (args.input !== 'expected') {
        throw new UserInputError('Form Arguments invalid', {
          invalidArgs: Object.keys(args),
        });
      }
    },
  },
};

响应将返回:

在这里插入图片描述
其它错误
如果需要定义特定于您的应用程序的其他错误代码,则可以使用 ApolloError 基类。

new ApolloError(message, code, additionalProperties);

掩盖和记录错误

对于客户端响应
Apollo Server 构造函数接受一个 formatError 函数,该函数在传递回客户端的每个错误上运行。这可用于掩盖错误以及记录日志。
请注意,虽然这会更改发送到客户端的错误,但不会更改发送到 Apollo Studio 的错误。如果需要此行为,请参见下面的 For Apollo Studio 报告中的 rewriteError 函数。
此示例演示当错误消息以 Database Error: 开头时抛出另一个错误:

const server = new ApolloServer({
  typeDefs,
  resolvers,

  formatError: (err) => {
    // Don't give the specific errors to the client.
    if (err.message.startsWith("Database Error: ")) {
      return new Error('Internal server error');
    }
    // Otherwise return the original error.  The error can also
    // be manipulated in other ways, so long as it's returned.
    return err;
  },
});

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

formatError(一个GraphQLError)接收到的错误实例包含一个 originalError 属性,该属性表示在解析器中引发的原始错误。这可以用于 instanceof 检查特定的错误类,例如 AuthenticationError,ValidationError 等:

  /* ... */
  formatError(err) {
    if (err.originalError instanceof AuthenticationError) {
      return new Error('Different authentication error message!');
    }
  },
  /* ... */

要针对 formatError 接收到的错误进行特定于上下文的调整(例如,本地化或个性化设置),请考虑使用 didEncounterErrors 生命周期挂钩将其他属性附加到错误,可以在 formatError 中访问和利用附加属性。

七、权限认证

如何在 GraphQL API 中授权用户和权限控制。
在构建GraphQL端点时的某个时间点(可能很早),您可能不得不面对一个问题,即如何控制谁可以看到您的API中的数据并与之交互。
身份验证是确定用户是否已登录,然后确定某人是哪个用户。然后,授权将决定用户有权执行或查看的内容。
一旦知道用户尝试发出请求,本文将主要侧重于如何为您的 schema 设置授权,但是我们将通过一个身份验证示例来了解我们正在做的事情的背景。

将用户信息放到 context 中

在弄清楚用户权限之前,我们必须先弄清楚如何识别用户。从 HTTP 标头到 JSON Web Token,有多种方法可以处理用户身份验证,但是一旦拥有用户,控制访问就非常相似。

我们将以 HTTP 授权标头中的登录令牌为例。

// using apollo-server 2.x
const { ApolloServer } = require('apollo-server');

const server = new ApolloServer({
 typeDefs,
 resolvers,
 context: ({ req }) => {
   // Note! This example uses the `req` object to access headers,
   // but the arguments received by `context` vary by integration.
   // This means they will vary for Express, Koa, Lambda, etc.!
   //
   // To find out the correct arguments for a specific integration,
   // see the `context` option in the API reference for `apollo-server`:
   // https://www.apollographql.com/docs/apollo-server/api/apollo-server/

   // Get the user token from the headers.
   const token = req.headers.authorization || '';

   // try to retrieve a user with the token
   const user = getUser(token);

   // add the user to the context
   return { user };
 },
});

server.listen().then(({ url }) => {
 console.log(`🚀 Server ready at ${url}`)
});

那么,这里到底发生了什么?此代码块使用 Apollo Server 2.0 设置新的 GraphQL 服务器。新版本的 Apollo Server 简化了用于创建新服务器的 API,并具有一些更智能的默认值。你可以在这里读更多关于它的内容!

在此构造函数中,我们将类型定义和解析器传递给构造函数以及用于构建上下文对象的函数。上下文对象是传递给每个级别的每个解析器的对象,因此我们可以在 schema 代码中的任何位置访问它。在这里我们可以存储数据提取程序,数据库连接以及(方便地)有关发出请求的用户的信息。

由于每次新请求都会重新生成上下文,因此我们不必担心在执行结束时清理用户数据。

这里的上下文函数查看请求标头,提取名为 authorization 的标头,并将其存储到变量中。然后,它将使用该令牌调用 getUser 函数,并期望在令牌有效的情况下返回用户。之后,它返回一个包含(潜在)用户的上下文对象,供我们所有的解析器使用。

对于每种身份验证方法,检索用户的细节将有所不同,但是最终部分每次都会看起来相同。您的 schema 需要的授权可能要求您仅在上下文中添加 { loggingIn: true },但可能还需要 ID 或角色,例如 {user: {id: 12345,role: [‘user’, ‘admin’ ]}}。

在下一节中,我们将探讨使用现在需要保护用户信息的用户信息的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1752.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vite+Vue+Electron环境搭建

因为electron可以直接加载html文件,也可以直接加载url链接,所以,我们可以在调试过程中使用url地址,来动态显示我们的改变过程。 electron简单来说就是对html的一种封装,所以我们先来搭建vue的开发环境,这里…

LQ0135 左孩子右兄弟【DFS+二叉树】

题目来源:蓝桥杯2021初赛 C A组H题 题目描述 对于一棵多叉树,我们可以通过“左孩子右兄弟” 表示法,将其转化成一棵二叉树。 如果我们认为每个结点的子结点是无序的,那么得到的二叉树可能不唯一。 换句话说,每个结点可…

并发编程之ForkJoin框架

什么是 Fork/Join 框架 Fork/Join 是从 java7 开始提供的并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务的结果,得到大任务结果的框架. 如下图: Fork/Join 的特性 ForJoinPool 不是为了替代 Execu…

毕业仅1年,干Python赚了50W!网友:不是吹的

前言 惊讶 ​Py现状:Python职位月薪5W起? 其他程序员:心态塌了! 秒杀各行业薪资榜单,拿下编程语言排行榜的Python,工资真的如网上说的开挂了吗?有人在网上发现这样的一条评论信息&#xff1a…

公众号网课查题接口题库

公众号网课查题接口题库 本平台优点: 多题库查题、独立后台、响应速度快、全网平台可查、功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 题库:题库后台(点击跳转&#xf…

Navicat 现已支持 OceanBase 企业版

近期,PremiumSoft CyberTech Limited 公司发布了 Navicat 16.1.3 版本,正式支持蚂蚁集团旗下的 OceanBase 企业版(MySQL 兼容模式)。此次合作旨在帮助用户通过 Navcicat 进行 OceanBase 企业版的数据库开发及管理,更大…

说说 Redis 事务

Redis 事务简介# Redis 只是提供了简单的事务功能。其本质是一组命令的集合,事务支持一次执行多个命令,在事务执行过程中,会顺序执行队列中的命令,其他客户端提交的命令请求不会插入到本事务执行命令序列中。命令的执行过程是顺序…

MPLS综合实验

目录 实验要求 划分IP地址 首先对MPLSVPN骨干网络进行配置 首先配置IP地址 启动IGP协议 激活MPLS和LDP VRF空间的创建 将接口划入到VRF空间中 R1和R5通过静态路由在CE和PE上配置 建立MP-BGP 对站点R1和R5进行配置 首先把IP给配置好 在VRF空间中发布路由信息 对站点…

2000-2020上市公司全要素生产率LP方法含原始数据和Stata代码

1、时间:2000-2020年 2、指标包括:stkcd、year、证券代码、固定资产净额、营业总收入、营业收入、营业成本、销售费用、管理费用、财务费用、支付给职工以及为职工支付的现金、员工人数、折旧摊销、行业代码、上市日期、AB股交叉码、退市日期、年末是否…

windows下用Java跑通spark官方文档的quick-start

这里写自定义目录标题前置环境官方示例三个小坑maven文件引用不明确未传递master url前置环境 见上一篇:https://blog.csdn.net/shuzip/article/details/115606522 官方示例 https://spark.apache.org/docs/3.1.1/quick-start.html /* SimpleApp.java */ import…

廊坊特色农业 国稻种芯·中国水稻节:河北复合农业促增收

廊坊特色农业 国稻种芯中国水稻节:河北复合农业促增收 新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健康大会报道:河北廊坊安次区“稻蟹共作”新模式 特色农业…

Codeforces Round #773 (Div. 2)

A. Hard Way 题目链接:Problem - A - Codeforces 样例输入: 5 8 10 10 4 6 2 4 6 0 1 4 2 14 1 11 2 13 2 0 0 4 0 2 4 0 1 1 1 0 0样例输出: 0.0000000 0 2.0000 0.00 1题意:给定一个三角形的三个顶点,输入保证三角…

echarts画各种形状水波图

各种形状水波图 代码 用的是echarts绘制&#xff0c;echarts相关api可以参考echarts官网&#xff0c;形状修改series.shape即可修改形状&#xff0c;这里用的是SVG路径 <html><head><meta charset"utf-8"><link href"https://fonts.google…

jQuery网页开发案例:jQuery常用API--jQuery 尺寸、位置操作及 电梯导航案例和节流阀(互斥锁)

jQuery 尺寸 以上参数为空&#xff0c;则是获取相应值&#xff0c;返回的是数字型。如果参数为数字&#xff0c;则是修改相应值。参数可以不必写单位。这个width方法不包含边框 innerWidth()包含widthpadding 注意这个要大写 outerWidth()包含width padding border outerW…

(JavaSE) 数组

文章目录1. 数组的作用2. 数组的创建及初始化2.1 数组的创建2.2 数组的初始化3. 数组的使用3.1 数组中元素的访问3.2 遍历数组方法4. 数组是引用类型4.1 JVM中的内存有那些4.2 数组如何开辟空间4.3 数组 null 的意思4.4 引用不能同时指向多个对象4.5 数组作为方法返回值5. 二维…

【一键生成】3DMAX配景楼生成插件使用教程

3DMAX室外设计师常常需要创建各种场景配楼&#xff0c;为了解决大场景制作难的情况&#xff0c;3dMax配景楼生成插件是一款傻瓜式的插件或许更能快速让你从繁重的体力劳动中解脱出来&#xff01; 【安装方法】 方法一&#xff1a;拖动插件文件到3dMax窗口。 方法二&#xff1a;…

MySQL 主要线程

文章目录MySQL 主要线程1. Master thread2. io thread3. purge thread4. page Cleaner ThreadMySQL 主要线程 1. Master thread Master thread有四大循环&#xff0c;分别是loop,background loop&#xff0c;suspend loop&#xff0c;flush loop。且四大循环的作用如下: loop…

第二篇 基于自然语言处理的漏洞检测方法综述

杨伊等 来源&#xff1a;计算机研究与发展 目录 1 相关技术 1.1 自然语言处理 1.2 漏洞检测与分析 据2021年CVE漏洞趋势安全报告&#xff0c;当前漏洞类型占比最大的5类漏洞分别是代码执行、拒绝服务、溢出、跨站脚本以及信息获取。基于自然语言处理技术实现漏洞检测的研究…

STM32F103实现激光测距传感器测距WT-VL53L0 L1

目录 本博客将采用标准库和HAL库实现 所用设备选择 引脚说明 与单片机的接线表 标准库实现 HAL库实现 本博客将采用标准库和HAL库实现 所用设备选择 单片机型号&#xff1a;STM32F103C8T6 激光测距传感器型号&#xff1a;WT-VL53L0 L1 采用串口TTL电平输出&#xff0c;可…

CSDN云IDE初次测评体验

CSDN云IDE初次测评体验 文章目录CSDN云IDE初次测评体验一、前言二、云IDE产品介绍三、云IDE使用教程1、尝试编写Python爬虫代码2、尝试编写Python可视化代码3、尝试连接MySQL数据库四、最后我想说一、前言 最近一直有收到CSDN官方私信参加这个测评云IDE活动&#xff0c;刚好这…