首页 > 解决方案 > 订阅未返回 201 Created HTTP 状态码

问题描述

我正在尝试使用 Microsoft Graph 订阅订阅用户的邮箱。我尝试仅使用“created”changeType 订阅特定用户的邮箱,该邮箱是通过在 AD 中使用我公司租户上的客户端凭据创建的令牌访问的(应用程序注册)。这是在我的开发环境(Laravel 框架,使用 Laravel Valet + ngrok)中完成的。

我可以在 MS 端成功创建订阅,使通知 URL 成为 ngrok URL,并且我能够通过验证等,但 MS 似乎没有返回确认订阅已创建,如它所说的“201 Created”响应它应该在文档中。

我可以确认订阅有效,因为我可以向该邮箱发送电子邮件,并且 ngrok 捕获包含正确信息的请求 - 只是 webhook 的初始设置在成功创建时不会返回 201。

我想得到这个确认,这样我就可以将 webhook 的 ID 等存储在应用程序中以供进一步使用(更新 cron 等的到期时间)。

抱歉,如果我没有提交足够的信息来明确问题 - 请询问相关细节。

我应该如何处理这个?

编辑 - 包括代码示例和路由

我使用的代码是一个自定义类,所以我不能包含所有内容,但这就是它的构建方式:

微软.php

    public function subscribe($resource)
    {
        $this->verb = "POST";

        $this->endpoint = "/subscriptions";

        $this->body = [
            "notificationUrl" => config('app.env') === 'production'
                ? env('APP_URL') . route('ms', null, false)
                : env('NGROK_URL') . route('ms', null, false),
            "resource" => $resource,
            "expirationDateTime" => Carbon::now('UTC')->addDay(),
            "latestSupportedTlsVersion" => "v1_2"
        ];

        return $this;
    }

    public function changes($array)
    {
        $this->body['changeType'] = implode(",", $array);

        return $this;
    }

    public function send()
    {
        $token = $this->getToken()->token;

        $this->headers['Authorization'] = "Bearer $token";

        try {
            $response = $this->client
                ->request($this->verb, env('GRAPH_BASE_URL') . $this->endpoint, [
                    'headers' => $this->headers,
                    'body' => json_encode($this->body, JSON_UNESCAPED_SLASHES)
                ]);

            return json_decode($response->getBody());
        } catch (RequestException $e) {
            echo Psr7\str($e->getRequest());
            if ($e->hasResponse()) {
                echo Psr7\str($e->getResponse());
            }
        }
    }

运行的命令的代码:

    public function handle()
    {
        $client = new MicrosoftClient();

        $webhookUrl = "users/" .
            env('AZURE_USER_ID') .
            "/mailFolders('Inbox')/messages";

        $changes = ['created'];

        $client->subscribe($webhookUrl)->changes($changes)->send();
    }

我的应用程序逻辑上的 POST 路由:

Route::post('[my webhook url]', function (Request $request) {
    if ($request->query('validationToken')) {
        // MS requires that successful requests must send back a 200 status code
        // using a plain text response
        return response($request->query('validationToken', 200))
            ->header('Content-Type', 'text/plain');
    } else {
        // just a regular webhook create/update...
        Log::info('Got email' . $request->input('value.resourceData'));
        Log::debug($request);
    }
})->name('ms');

^ 在 else 语句中,我将日志放在那里以查看 Laravel 是否捕捉到任何额外的响应,但 201 不存在。不过,实际的 webhook 通知已被捕获。

这是发送前的请求转储,为了美观,JSON 格式:

POST /v1.0/subscriptions HTTP/1.1
User-Agent: GuzzleHttp/6.5.1 curl/7.68.0 PHP/7.4.3
Host: graph.microsoft.com
Content-Type: application/json
Authorization: Bearer [token]

{
  "notificationUrl":"[ngrok url]/[my chosen webhook endpoint]",
  "resource":"users/[user id]/mailFolders('Inbox')/messages",
  "expirationDateTime":"[24 hours after request made]",
  "latestSupportedTlsVersion":"v1_2",
  "changeType":"created"
}

这是我从 MS 收到的用于验证订阅的内容:

POST /[my webhook url]?validationToken=Validation%3a+Testing+client+application+reachability+for+subscription+Request-Id%3a+262d7fae-31c3-4541-8de0-c1fc26ddd41b HTTP/1.1

Host: ticket-system.test:60
Content-Length: 0
Content-Type: text/plain; charset=utf-8
X-Forwarded-For: 40.113.95.219
X-Forwarded-Proto: https
X-Original-Host: [ngrok url]

这是我发回给 MS 的验证响应(验证令牌位):

HTTP/1.1 200 OK
Server: nginx/1.15.11
Content-Type: text/plain; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/7.4.3
Cache-Control: no-cache, private
Date: Fri, 03 Apr 2020 08:42:34 GMT
Set-Cookie: XSRF-TOKEN=[XSRF token]; expires=Fri, 03-Apr-2020 10:42:34 GMT; Max-Age=7200; path=/
Set-Cookie: [sluggified_app_name]_session=[session]; expires=Fri, 03-Apr-2020 10:42:34 GMT; Max-Age=7200; path=/; httponly


75

Validation: Testing client application reachability for subscription Request-Id: 262d7fae-31c3-4541-8de0-c1fc26ddd41b

0

这就是 ngrok 似乎要捕捉到的一切,一个 200 响应代码似乎只是在创建 webhook 之前的“验证”请求:

链接到 Webhook 响应示例抱歉,我无法在此处发布图片,因为我是新成员。

如您所见,我似乎没有得到任何确认 webhook 详细信息的信息。

标签: microsoft-graph-api

解决方案


主要问题是通过查看代码未使用(记录、存储等)来自订阅创建请求的响应。(句柄方法的最后一行)。
如评论中所述,订阅信息将在响应中,而不是在到达端点的验证请求中。


推荐阅读