自定义 HTTPS 端点 [已弃用]
您可定义自定义 HTTPS 端点来创建特定于应用的 API 路由或与外部服务集成的 Webhook。自定义端点使用您编写的无服务器函数来处理针对特定 URL 和 HTTP 方法的传入请求。
注意
HTTPS endpoints私有端点 不支持自定义 端点。
端点使用标准的加密 HTTPS 请求,这意味着您无需安装任何数据库驱动程序或偏好明确的库即可调用它们。相反,您可以从任何 HTTP 客户端发送如下请求:
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "name": "Casey" }'
端点的结构
端点处理发送到特定 URL 的一个或多个 HTTP 方法。
基本 URL
应用中的端点共享一个基本 URL。该 URL 使用 App ID 来专门指向您的应用。
全局部署的应用程序采用以下格式:
https://data.mongodb-api.com/app/<App ID>/endpoint
本地部署应用中的终结点使用特定于该应用的部署地区的基本 URL(例如 us-east-1
)
https://<Region>.aws.data.mongodb-api.com/app/<App ID>/endpoint
端点路由
每个 HTTPS 端点都有一个用作端点名称的路由。端点的路由是任意的,并且特定于您的应用。但是,它出现在端点 URL 路径中,因此应代表路由执行的操作。
路由名称必须以正斜杠 (/
) 开头,可包含其他正斜杠来表示嵌套路径。
/my/nested/route
您可以通过将端点的路由附加到应用的基本 URL 并发送 HTTP 请求来调用该端点。
https://data.mongodb-api.com/app/<App ID>/endpoint/my/nested/route
HTTP 方法
应用中的每个端点都会处理一个或多个 HTTP方法 对于给定的路线。POST
示例,您可能有一个路由,它可接受用于创建新资源的GET
请求。
您可以定义多个自定义端点,这些端点为同一路由提供服务,但处理不同的请求方法。或者,您可以为处理所有方法的路由定义单个端点。
自定义端点支持以下标准 HTTP 方法:
创建自定义 HTTPS 端点
您可以通过 App Services UI 或使用 App Services CLI 部署配置文件,来配置应用的 Data API:
单击左侧导航菜单中的 HTTPS Endpoints ,然后单击Add An Endpoint 。
定义端点 Route。路由名称必须以正斜杠 (
/
) 开头,可包含其他正斜杠来表示嵌套路径。从下拉菜单中为端点选择 HTTP 方法。您可以选择一种特定方法(例如
GET
或POST
)或配置端点以接受任何 HTTP 方法(即ANY
)。选择响应类型,JSON 或 EJSON。您可以启用 Respond With Result 以自动将端点函数的返回值包含为响应正文。
编写一个端点函数,用于处理对端点的请求。或者,按名称指定现有函数。
为了提高安全性,您可以配置请求授权。
保存 Data API 配置。
配置访问权限以允许请求安全地读取和写入数据。
保存并部署应用程序。
拉取应用的最新版本。
appservices pull --remote="<Your App ID>" 为自定义端点定义配置对象。
http_endpoints/config.json[ { "route": "<Endpoint route name>", "http_method": "<HTTP method>", "function_name": "<Endpoint function name", "validation_method": "<Authorization scheme>", "respond_result": <boolean>, "fetch_custom_user_data": <boolean>, "create_user_on_auth": <boolean>, "disabled": <boolean> } ] 为一个或多个集合定义规则。
data_sources/mongodb-atlas/<db>/<collection>/rules.json{ "database": "<Database Name>", "collection": "<Collection Name>", "roles": [<Role>], "filters": [<Filter>] } 部署您的应用。
appservices push
身份验证
自定义端点在特定用户的上下文中运行,这允许您的应用强制执行规则并验证每个请求的文档模式。
默认情况下,端点使用“应用程序身份验证”,要求每次请求都包含一个应用程序用户的凭据,如 API 密钥或 JWT。您还可以配置其他自定义身份验证方案,以满足应用程序的需求。
有关如何对请求进行身份验证的示例,请参阅对 Data API 请求进行身份验证。
应用程序身份验证要求用户使用您为应用启用的身份验证提供者。请求可以包含由身份验证提供者授予的访问令牌,也可以包含用户登录时使用的凭据(例如他们的 API 密钥或电子邮件和密码)。
用户ID身份验证将所有请求作为单个预选的应用程序用户运行。 如果无论谁调用端点,所有请求都应具有相同的权限,这非常有用。
要选择用户,请在端点配置中指定其用户帐户ID 。
[ { ..., "run_as_user_id": "628e47baf4c2ac2796fc8a91" } ]
脚本身份验证会调用函数来确定请求以哪个应用程序用户身份运行。 您可以使用它来实现自定义身份验证和授权方案。
该函数必须以ID string或 的形式返回现有应用程序用户的帐户{ "runAsSystem": true }
MongoDBCRUD,以对 和聚合 API 具有完全访问权限并且不受任何规则、角色或有限权限约束的 系统用户 运行请求。
若要定义函数,请在端点配置中指定源代码。
[ { ..., "run_as_user_id_script_source": "exports = () => {return \"628e47baf4c2ac2796fc8a91\"}" } ]
系统身份验证将端点配置为以系统用户身份运行,该系统用户无需凭证,对MongoDB CRUD和聚合 API 具有完全访问权限,并且不受任何规则、角色或有限权限的约束。
[ { ..., "run_as_system": true } ]
提示
默认情况下,您在用户界面中创建的新端点使用系统身份验证。
授权
端点可以要求已通过身份验证的用户在请求中提供其他授权信息。您可以通过配置端点函数来为每个自定义端点定义授权方案。
端点本身支持一组内置授权方案,这些方案使用密钥字符串来证明请求已获授权。您还可以定义自定义授权方案,可以将其与内置方案一起使用或代替内置方案。
要了解如何为特定函数配置授权,请参阅定义函数。
内置授权模式
端点支持以下内置授权方案:
所有通过身份验证的用户都有权调用端点。经过身份验证的请求不需要包含授权信息。
经过身份验证的用户必须证明他们有权通过包含特定string作为 secret
查询参数的值来调用端点。
您在string 密钥 中定义该 ,并在端点配置中按名称引用该密钥。
[ { ..., "verification_method": "SECRET_AS_QUERY_PARAM", "secret_name": "secret_verification_string" } ]
要学习;了解如何在请求中包含密钥,请参阅授权请求。
经过身份验证的用户必须通过包含 Endpoint-Signature
标头来证明他们有权调用端点,该标头包含从请求正文生成的十六进制编码的 HMAC SHA-256 哈希和密钥string 。
您在string 密钥 中定义该 ,并在端点配置中按名称引用该密钥。
要学习;了解如何对请求进行签名,请参阅授权请求。
自定义授权模式
您可以定义自定义授权表达式,以确定是否允许运行传入的已验证请求。该表达式针对每个请求进行计算,并且其计算结果必须为 true
才能允许请求。如果表达式的计算结果为 false
,则请求不会获得授权并出现错误,以失败告终。未通过授权的请求不计入应用的计费使用量。
授权表达式可使用 %%user
等变量,根据调用用户的数据进行授权,或使用 %%request
等变量,根据每次传入请求的具体情况做出决定。
要定义自定义授权方案,请在端点函数的配置中指定以下表达式:
[ { ..., "can_evaluate": { "%%request.requestHeaders.x-secret-key": "my-secret" } } ]
写入端点函数
每个自定义端点都与一个函数相关联,该函数在端点接收到传入请求时运行。在该函数中,您可以从 npm 导入库,连接到已链接的 MongoDB Atlas 集群,调用其他无服务器函数。
要在 App Services 用户界面中创建端点时定义新函数,请导航到 Function 部分,然后从下拉列表中选择 + New Function。
根据工作流程,您还可以定义和编辑端点处理程序函数:
在 App Services UI 的 Functions 页面。
在使用 App Services CLI 的应用程序的
functions
目录中。在使用 Admin API 的客户端中。
端点函数总是接收两个参数:
有关示例函数以及示例请求和响应,请参阅示例。
访问请求数据
自定义端点 Request
对象表示调用端点的 HTTP 请求。您可以访问传入请求的标头、查询参数和正文数据。
{ "headers": { "<Header>": ["<Header Value>"] }, "query": { "<Query Parameter>": "<Parameter Value>" }, "body": <BSON.Binary> }
字段 | 说明 | |||||
---|---|---|---|---|---|---|
query | 一个对象,其中每个字段均会将 URL 查询参数映射到其值。如果在查询字符串中多次使用某个密钥,则在此对象中仅表示第一次出现的情况。要使用完整的查询字符串,请使用 context.request.rawQueryString。 例子以下
| |||||
headers | 一个对象,其中每个字段将请求标头名称映射到一个或多个值的数组。 例子
| |||||
body | 包含请求正文的 BSON.Binary 对象。如果请求不含正文,则此值为 要访问请求正文中的数据,需要序列化以下二进制文件:
|
返回 HTTPS 响应
自定义端点 Response
Realm 对象允许你配置发送回调用方的 HTTPS 响应。你可以制定状态代码、自定义标头以及在响应正文中包含数据。
方法 | 说明 | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
setStatusCode(code) - code: number | 设置 HTTP 响应状态代码。 例子
| |||||||||
setBody(body) - body: string | BSON.Binary | 设置 HTTP 响应正文。 如果 例子
| |||||||||
setHeader(name, value) - name: string - value: string | 将 例子
| |||||||||
addHeader(name, value) - name: string - value: string | 将 例子
|
例子
考虑一个端点函数,它解析传入的 POST
请求的正文,将解析后的正文存储在 MongoDB 集合中,然后响应调用方:
exports = async function MyCustomEndpoint(request, response) { try { // 1. Parse data from the incoming request if (request.body === undefined) { throw new Error(`Request body was not defined.`); } const body = JSON.parse(request.body.text()); // 2. Handle the request const { insertedId } = await context.services .get("mongodb-atlas") .db("myDb") .collection("myCollection") .insertOne({ date: new Date(), requestBody: body }); // 3. Configure the response response.setStatusCode(201); // tip: You can also use EJSON.stringify instead of JSON.stringify. response.setBody( JSON.stringify({ insertedId, message: "Successfully saved the request body", }) ); } catch (error) { response.setStatusCode(400); response.setBody(error.message); } };
此函数接收以下 POST
请求:
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/custom" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "type": "event", "date": "2024-01-01T00:00:00.000Z", "name": "New Year Begins", "comment": "Happy New Year!" }'
{ "message": "Successfully saved the request body", "insertedId": "639a521bbdec9b85ba94014b" }
该函数验证传入请求的正文已定义后,会将解析后的正文作为新文档存储在名为 myCollection
的集合中。生成的输出显示配置的响应,其中包括自定义消息和 insertedId
。
调用自定义端点
您可从任意标准 HTTPS 客户端调用自定义端点。
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "name": "Casey" }'
发出请求时需要使用 HTTP/1.1 或更高版本。
选择响应数据格式
请求可以包含 Accept
标头,以请求响应正文的特定数据格式(JSON 或 EJSON)。如果请求不包含有效的 Accept
标头,则响应将使用端点配置中指定的默认数据格式。
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello/latest" \ -X GET \ -H "Accept: application/ejson" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6"
{ "greeting": "Hello, Leafie!", "date": { "$date": { "$numberLong": "1654589430998" } } }
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello/latest" \ -X GET \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6"
{ "greeting": "Hello, Leafie!", "date": "2022-06-07T08:10:30.998Z" }
验证请求
如果端点配置为使用应用程序身份验证,则必须在每个请求中包含有效的用户访问令牌或登录档案。
通常,使用访问令牌的持有者身份验证具有更高的吞吐量,并且比凭证标头更安全。尽量使用访问令牌,而不是凭证标头。该令牌允许运行多个请求,而无需重新对用户进行身份验证。此外,它还允许从强制执行 CORS 的 Web 浏览器发送请求。
要使用访问令牌,请先通过 App Services 身份验证提供者来对用户进行身份验证。然后,获取从 App Services 返回的访问令牌,并使用持有者令牌方案将其包含在请求的“授权”标头中。有关如何获取和使用访问令牌的详情,请参阅持有者令牌身份验证。
curl -X GET \ -H 'Authorization: Bearer <AccessToken>' \ -H 'Content-Type: application/json' \ https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello
或者也可以在请求标头中包含用户的有效登录档案。
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "email: bob@example" \ -H "password: Pa55w0rd!" \ -d '{ "name": "Bob" }'
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "name": "Alice" }'
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "jwtTokenString: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0LWN1c3RvbS1lbmRwb2ludHMtZWhtenQiLCJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoyMTQ1OTE2ODAwfQ.pIMvnXWrcDvmPzmE33ZPrwkBAFSwy-GxW8sP-qLtYiw" \ -d '{ "name": "Carlos" }'
重要
请勿在面向用户的客户端中使用 API 密钥
如果您从浏览器或其他面向用户的客户端应用程序进行身份验证,请避免使用 API 密钥登录。请改用其他接受用户提供的档案的身份验证提供者。切勿在本地存储 API 密钥或其他敏感档案。
授权请求
根据端点配置的不同,您的请求可能需要包含其他授权信息。
所有通过身份验证的用户都有权调用端点。经过身份验证的请求不需要包含授权信息。
经过身份验证的用户必须证明他们有权通过将端点的密钥string作为 secret
查询参数的值来调用端点。
例子
以下 curl
请求将密钥查询参数验证与密钥string "Super5ecr3tPa55w0rd"
结合使用:
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/passwordRequired?secret=Super5ecr3tPa55w0rd" \ -X GET \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "data": "VGhpcyBpcyBzb21lIGRhdGEgdGhhdCB3YXMgZW5jb2RlZCBhcyBhIEJhc2U2NCBBU0NJSSBzdHJpbmc=" }'
经过身份验证的用户必须证明他们有权调用端点,方法是包含Endpoint-Signature
256标头,该标头包含根据请求正文和端点的密钥 生成的十六进制编码的 HMAC SHA-string 哈希值。
Endpoint-Signature: sha256=<hex encoded hash>
您可以使用以下函数生成有效负载签名:
/** * Generate an HMAC request signature. * @param {string} secret - The secret validation string, e.g. "12345" * @param {object} body - The endpoint request body e.g. { "message": "MESSAGE" } * @returns {string} The HMAC SHA-256 request signature in hex format. */ exports = function signEndpointRequest(secret, body) { const payload = EJSON.stringify(body); return utils.crypto.hmac(payload, secret, "sha256", "hex"); };
例子
以下curl
请求包含使用密钥值Super5ecr3tPa55w0rd
签名的有效负载签名标头:
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/sendMessage" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -H "Endpoint-Signature: sha256=d4f0537db4e230d7a6028a6f7c3bb1b57c9d16f39176d78697e559ac333e0b36" \ -d '{ "message": "Hello!" }'