AMP 電子郵件中的 CORS
重要事項:本文件不適用於您目前選取的格式 廣告!
跨來源資源共用 (CORS) 是一種機制,透過使用 HTTP 標頭來告知瀏覽器,哪些來源可以使用 XHR 存取資源。AMP 電子郵件擴展了這種機制,加入 HTTP 標頭,以類似的方式告知電子郵件用戶端,哪些寄件者可以存取這些資源。
目前有兩個版本的機制。暫時建議您在伺服器端同時支援這兩個版本。
版本 2
當電子郵件透過 amp-form
、amp-list
或任何其他以 XHR 為基礎的機制發出要求時,電子郵件用戶端會包含以下 HTTP 標頭
AMP-Email-Sender
,設定為電子郵件寄件者的電子郵件地址。
它預期 HTTP 回應會傳回以下標頭
AMP-Email-Allow-Sender
,其值與要求中的AMP-Email-Sender
相同,或使用*
表示允許所有寄件者電子郵件。
範例
使用者在電子郵件用戶端中開啟來自 sender@company.example
的電子郵件,網址為 https://emailclient.example/myinbox
。電子郵件使用 AMP 電子郵件,並使用 amp-list
從 https://company.example/data.json
載入資料。
電子郵件用戶端傳送 HTTP 要求至 https://company.example/data.json
,並設定以下標頭
AMP-Email-Sender: sender@company.example
電子郵件用戶端預期 HTTP 回應包含以下標頭
AMP-Email-Allow-Sender: sender@company.example
或者,允許在任一標頭中使用 *
(但不建議)。
版本 1 (已淘汰)
在版本 1 中,電子郵件用戶端使用查詢字串參數,而非 HTTP 標頭來指示寄件者電子郵件。它也提供 Origin
標頭,並要求在回應中提供 Access-Control-Allow-Origin
標頭,如同網站上的 CORS。
當電子郵件透過 amp-form
、amp-list
或任何其他以 XHR 為基礎的機制發出要求時,電子郵件用戶端會包含以下 HTTP 標頭
Origin
,值為用於顯示電子郵件的頁面來源。
URL 也始終具有查詢字串,其中 __amp_source_origin
參數設定為電子郵件寄件者的電子郵件地址。
它預期 HTTP 回應包含以下標頭
Access-Control-Allow-Origin
,其值與要求中的Origin
相同AMP-Access-Control-Allow-Source-Origin
,其值與要求中的__amp_source_origin
查詢字串參數相同。Access-Control-Expose-Headers
,設定為AMP-Access-Control-Allow-Source-Origin
範例
使用者在電子郵件用戶端中開啟來自 sender@company.example
的電子郵件,網址為 https://emailclient.example/myinbox
。電子郵件使用 AMP 電子郵件,並使用 amp-list
從 https://company.example/data.json
載入資料。
電子郵件用戶端傳送 HTTP 要求至 https://company.example/data.json?__amp_source_origin=sender@company.example
(請注意新增的查詢字串),並設定以下標頭
Origin: https://emailclient.example
電子郵件用戶端預期 HTTP 回應包含以下標頭
Access-Control-Allow-Origin: https://emailclient.example
AMP-Access-Control-Allow-Source-Origin: sender@company.example
Access-Control-Expose-Headers: AMP-Access-Control-Allow-Source-Origin
請注意,此版本不支援在 AMP-Access-Control-Allow-Source-Origin
標頭中使用 *
。
實作 CORS
以下是在伺服器端實作 CORS 以支援版本 1 和版本 2 的建議步驟
當您收到 HTTP 要求時,請檢查是否已設定 Origin
和 AMP-Email-Sender
HTTP 標頭。
- 如果已設定
AMP-Email-Sender
標頭- 讓senderEmail 為
AMP-Email-Sender
標頭的值。 - 檢查 senderEmail 是否為您擁有或信任的電子郵件地址。如果不是,請拒絕要求。
- 將回應標頭
AMP-Email-Allow-Sender
設定為 senderEmail。
- 讓senderEmail 為
- 如果已設定
Origin
標頭,但未設定AMP-Email-Sender
- 讓 requestOrigin 為
Origin
標頭的值。 - 將回應標頭
Access-Control-Allow-Origin
設定為 requestOrigin。 - 檢查 URL 是否包含
__amp_source_origin
查詢字串參數。如果沒有,請拒絕要求。 - 讓 senderEmail 為
__amp_source_origin
查詢字串參數的值。 - 檢查 senderEmail 是否為您擁有或信任的電子郵件地址。如果不是,請拒絕要求。
- 將回應標頭
AMP-Access-Control-Allow-Source-Origin
設定為 senderEmail。 - 將回應標頭
Access-Control-Expose-Headers
設定為AMP-Access-Control-Allow-Source-Origin
。
- 讓 requestOrigin 為
- 如果
Origin
和AMP-Email-Sender
都未設定,請拒絕要求。
範例 1
電子郵件用戶端傳送的要求
GET /data.json?__amp_source_origin=sender@company.example HTTP/1.1
Host: company.example
Origin: https://emailclient.example
User-Agent: EmailClientProxy
Accept: application/json
預期的回應標頭
Access-Control-Allow-Origin: https://emailclient.example
Access-Control-Expose-Headers: AMP-Access-Control-Allow-Source-Origin
AMP-Access-Control-Allow-Source-Origin: sender@company.example
說明
由於已設定 Origin
標頭,因此此要求使用 CORS 版本 1,並且需要設定上面列出的三個標頭。
範例 2
電子郵件用戶端傳送的要求
GET /data.json HTTP/1.1
Host: company.example
AMP-Email-Sender: sender@company.example
User-Agent: EmailClientProxy
Accept: application/json
預期的回應標頭
AMP-Email-Allow-Sender: sender@company.example
說明
由於已設定 AMP-Email-Sender
標頭,因此此要求使用 CORS 版本 2,並且僅需要 AMP-Email-Allow-Sender
標頭。
範例 3
電子郵件用戶端傳送的要求
GET /data.json?__amp_source_origin=sender@company.example HTTP/1.1
Host: company.example
Origin: https://emailclient.example
AMP-Email-Sender: sender@company.example
User-Agent: EmailClientProxy
Accept: application/json
預期的回應標頭
AMP-Email-Allow-Sender: sender@company.example
說明
Origin
和 AMP-Email-Sender
都已設定,表示用戶端同時支援這兩個版本。由於版本 2 優先,因此僅設定 AMP-Email-Allow-Sender
標頭,並且可以安全地忽略 Origin
和 __amp_source_origin
的值。
程式碼範例
PHP
if (isset($_SERVER['HTTP_AMP_EMAIL_SENDER'])) {
$senderEmail = $_SERVER['HTTP_AMP_EMAIL_SENDER'];
if (!isAllowedSender($senderEmail)) {
die('invalid sender');
}
header("AMP-Email-Allow-Sender: $senderEmail");
} elseif (isset($_SERVER['HTTP_ORIGIN'])) {
$requestOrigin = $_SERVER['HTTP_ORIGIN'];
if (empty($_GET['__amp_source_origin'])) {
die('invalid request');
}
$senderEmail = $_GET['__amp_source_origin'];
if (!isAllowedSender($senderEmail)) {
die('invalid sender');
}
header("Access-Control-Allow-Origin: $requestOrigin");
header('Access-Control-Expose-Headers: AMP-Access-Control-Allow-Source-Origin');
header("AMP-Access-Control-Allow-Source-Origin: $senderEmail");
} else {
die('invalid request');
}
Python (Django)
response = JsonResponse(...)
if request.META.HTTP_AMP_EMAIL_SENDER:
senderEmail = request.META.HTTP_AMP_EMAIL_SENDER
if not isAllowedSender(senderEmail):
raise PermissionDenied
response['AMP-Email-Allow-Sender'] = senderEmail
elif request.META.HTTP_ORIGIN:
requestOrigin = request.META.HTTP_ORIGIN
senderEmail = request.GET.get('__amp_source_origin')
if not isAllowedSender(senderEmail):
raise PermissionDenied
response['Access-Control-Allow-Origin'] = requestOrigin
response['Access-Control-Expose-Headers'] = 'AMP-Access-Control-Allow-Source-Origin'
response['AMP-Access-Control-Allow-Source-Origin'] = senderEmail
else
raise PermissionDenied
SSJS
<script runat="server" language="JavaScript">
Platform.Load("core", "1");
if (Platform.Request.GetRequestHeader("AMP-Email-Sender")) {
var senderEmail = Platform.Request.GetRequestHeader("AMP-Email-Sender")
if (isValidSender(senderEmail)) {
HTTPHeader.SetValue("AMP-Email-Allow-Sender", senderEmail)
} else {
Platform.Function.RaiseError("Sender Not Allowed",true,"statusCode","3");
}
} else if (Platform.Request.GetRequestHeader("Origin")) {
var requestOrigin = Platform.Request.GetRequestHeader("Origin")
if (Platform.Request.GetQueryStringParameter("__amp_source_origin")) {
var senderEmail = Platform.Request.GetQueryStringParameter("__amp_source_origin");
if (isValidSender(senderEmail)) {
HTTPHeader.SetValue("Access-Control-Allow-Origin", requestOrigin);
HTTPHeader.SetValue("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin");
HTTPHeader.SetValue("AMP-Access-Control-Allow-Source-Origin", senderEmail);
} else {
Platform.Function.RaiseError("Invalid Source Origin",true,"statusCode","3");
}
} else {
Platform.Function.RaiseError("Source Origin Not Present",true,"statusCode","3");
}
} else {
Platform.Function.RaiseError("Origin and Sender Not Present",true,"statusCode","3");
}
</script>
請造訪 Salesforce 開發人員文件,以深入瞭解 SSJS。
Node.js
使用官方支援的 @ampproject/toolbox-cors npm 套件。
-
作者: @fstanis