tencent cloud

Tencent Cloud EdgeOne

HTTPサーバーへのプッシュ

ダウンロード
フォーカスモード
フォントサイズ
最終更新日: 2026-10-16 11:38:30
AI翻訳
EdgeOneリアルタイムログ配信は、ログをカスタムインターフェースアドレスに配信することをサポートしています。コンソールまたはAPIを通じて設定できます。EdgeOneはHTTP POSTリクエストを通じてお客様が提供するバックエンドインターフェースアドレスを呼び出し、ログをHTTP Bodyでお客様が指定するサーバーに転送します。

操作手順

1. EdgeOneコンソールにログインし、左側のメニューバーで「サービス概要」に入り、「ウェブサイトのセキュリティ強化」内で設定が必要なサイトをクリックします。
2. サイト詳細ページで、「ログサービス」>「リアルタイムログ」をクリックします。
3. リアルタイムログページで、新しい配信タスクを作成をクリックします。
4. ログソース選択ページで、タスク名を入力し、ログタイプ、サービスリージョン、ログを配信するドメイン/L4プロキシインスタンス/エッジ関数を選択し、次へをクリックします。
5. 配信コンテンツ定義ページ:
(必須)プリセットフィールドリストで、配信が必要なログフィールドを選択します。
(任意)カスタムログフィールドを追加し、リクエストヘッダー、レスポンスヘッダー、Cookieヘッダーから指定したフィールド名の値を抽出することをサポートします。
(任意)配信ログのフィルタリング条件を設定します。デフォルトでは全量ログが配信されます。
(任意)詳細設定でサンプリング比率を設定します。デフォルトではサンプリングは無効で、100%のログが宛先に配信されます。
(任意)詳細設定で、ログ出力形式を設定します。デフォルト形式はJSON Linesです。
6. 宛先選択ページで、HTTPサービス(POST)を選択し、次へをクリックします。
7. 宛先情報ページで、関連する宛先およびパラメータ情報を入力します。
パラメータ名
説明
インターフェースアドレス
ログ受信インターフェースアドレスを入力してください。例えば、https://www.example.com/edgeone-logsです。
コンテンツ圧縮
ログコンテンツのサイズを削減し、トラフィックコストを節約するために、gzip を使用してログファイルを圧縮するにチェックを入れることでコンテンツ圧縮を有効にできます。EdgeOne は gzip 形式でログを圧縮してから転送し、HTTP ヘッダーContent-Encoding: gzipを追加して圧縮形式を示します。
オリジンサーバー認証
暗号化認証を選択した場合、ログをプッシュする際に認証情報を含めてオリジンサーバーに検証を依頼し、データソースの身元の安全性を保証します。認証アルゴリズムについては、認証アルゴリズム参考を参照してください。
カスタムHTTPリクエストヘッダー
EdgeOneがリクエストを開始する際に付与するHTTPヘッダーを追加してください。例えば、
ヘッダー log-source: EdgeOne を追加することで、ログのソースが EdgeOne であることを識別します。
ヘッダーBatchSize: ${batchSize}を追加することで、各POSTリクエストで配信されるログ件数を取得します。
説明
入力したヘッダー名が Content-Type など EdgeOne ログ配信でデフォルトで付与されるヘッダーである場合、入力したヘッダー値がデフォルト値を上書きします。
8. 配信をクリックします。
9. リアルタイムログ配信タスクは、設定段階でインターフェースの疎通性を検証するために、インターフェースアドレスへテストデータを送信して検証します。データ形式は以下の通りです:
{ "ClientState": "CH-AH", "EdgeResponseTime": 366, "RequestID": "13515444256055847385", "ClientRegion": "CN", "RemotePort": 443, "RequestHost": "www.tencent.com", "RequestMethod": "GET", "RequestUrlQueryString": "-", "RequestUrl": "/en-us/about.html", "RequestProtocol": "HTTP/2.0", "EdgeServerID": "336d5ebc5436534e61d16e63ddfca327-d41d8cd98f00b204e9800998ecf8427e", "RequestTime": "2022-07-01T02:37:13Z", "EdgeCacheStatus": "-", "EdgeResponseBytes": 39430, "EdgeResponseStatusCode": 200, "ClientIP": "0.0.0.0", "RequestReferer": "https://www.tencent.com/", "RequestUA": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1", "EdgeServerIP": "0.0.0.0", "RequestRange": "0-100/200", "EdgeInternalTime": 334, "RequestBytes": 237 }

関連参考

サーバー側ログ解析コード例

ソースサイト認証を有効にしていない場合、以下のPythonコードを参考に、サーバー側でリクエスト本文のログ内容を解析できます。
# Python標準ライブラリのモジュールをインポートします。
import time # 現在時刻を取得するために使用します。
import gzip # gzip圧縮データを処理するために使用します。
http.serverモジュールからHTTPServerおよびBaseHTTPRequestHandlerクラスをインポートします。
from http.server import HTTPServer, BaseHTTPRequestHandler
import json # JSONデータ形式を処理するために使用します。
# BaseHTTPRequestHandlerを継承するクラスを定義し、HTTPリクエストを処理するために使用します。
class Resquest(BaseHTTPRequestHandler):
# do_POSTメソッドを書き換えます。このメソッドは、サーバーがPOSTリクエストを受信したときに呼び出されます。
def do_POST(self):
# リクエストヘッダー情報を出力します。
print(str(self.headers))
# HTTPリクエストのコマンド(例:POST)を出力します。
print(self.command)
# リクエストボディの内容を読み取り、リクエストヘッダーのContent-Lengthフィールドに基づいて読み取り長を決定します。
req_datas = self.rfile.read(int(self.headers['content-length']))
try:
# リクエストボディの内容をデコードして出力することを試みます。
print(req_datas.decode())
except Exception as e:
# デコード中に例外が発生した場合、例外情報を出力します。
print(e)
# リクエストヘッダーにContent-Encoding: gzipがあるかどうかを確認し、ある場合はリクエストボディを解凍します。
if self.headers['Content-Encoding'] == 'gzip':
data = gzip.decompress(req_datas)
# 解凍後のgzipコンテンツを出力します。
print('---------------decompress gzip content-------------------------')
print(data.decode())
# リクエストのパスが「/edgeone-logs」であるかどうかを確認し、そうでない場合は404エラーを返します。
if self.path != '/edgeone-logs':
self.send_error(404, "Page not Found!")
return
# リクエストパスが正しい場合、レスポンスデータを準備します。
data = {
'result_code': '1',
'result_desc': 'Success',
'timestamp': int(time.time()) # 応答の現在のタイムスタンプ
}
# HTTPレスポンスステータスコード200を送信し、リクエストが成功したことを示します。
self.send_response(200)
# レスポンスヘッダーのContent-typeをapplication/jsonに設定します。
self.send_header('Content-type', 'application/json')
# レスポンスヘッダーの送信を終了します。
self.end_headers()
# レスポンスデータをJSON形式でレスポンスボディに書き込みます。
self.wfile.write(json.dumps(data).encode('utf-8'))
# 現在のスクリプトがメインプログラムとして実行されているかどうかを確認します。
if __name__ == '__main__':
# サーバーがリッスンするアドレスとポートを定義します。9002をカスタムポートに置き換えることができます。
host = ('', 9002)
# HTTPServerオブジェクトを作成し、リッスンアドレスとポート、およびリクエスト処理を行うリクエストハンドラクラスを渡します。
server = HTTPServer(host, Resquest)
# サーバー起動情報を出力します。
print("Starting server, listen at: %s:%s" % host)
# サーバーを起動し、外部から中断されるまで継続的に実行します。
server.serve_forever()

リクエスト認証アルゴリズム

如果您在推送目的地信息中、源站鉴权内选择了加密签名、可输入您自定义配置 SecretId 和 SecretKey、EdgeOne 将在请求 URL 中增加签名auth_key 和 access_key、签名算法详情如下:
1. リクエストURLの構成
以下に示すように、リクエストURLでは?の後にauth_keyとaccess_keyが付加されます。
http://DomainName[:port]/[uri]?auth_key=timestamp-rand-md5hash&access_key=SecretId
パラメータの説明:
timestamp:現在時刻をリクエストします。Unixの秒単位10桁のタイムスタンプを使用します。
rand:ランダムな数値。
access_key:インターフェースリクエスト元の身元を識別するために使用されます。つまり、お客様がカスタム設定したSecretIdです。
SecretKey:固定長32桁で、お客様がカスタム設定したSecretKeyです。
uri:リソース識別子です。例えば、/access_log/postです。
md5hash:md5hash = md5sum(string_to_sign)です。ここで、string_to_sign ="uri-timestamp-rand-SecretKey"です。md5アルゴリズムで計算された検証文字列であり、数字0-9と小文字の英字a-zが混在し、固定長は32文字です。
2. 計算例
入力パラメータは以下の通りと仮定します: インターフェースアドレス:https://www.example.com/access_log/post SecretId = YourID SecretKey = YourKey uri = /access_log/post timestamp = 1571587200 rand = 0
string_to_sign = "/access_log/post-1571587200-0-YourKey"
この文字列に基づいて計算します:
md5hash=md5sum("/access_log/post-1571587200-0-YourKey")=1f7ffa7bff8f06bbfbe2ace0f14b7e16
最終プッシュ時のリクエストurlは以下の通りです:
https://www.example.com/cdnlog/post?auth_key=1571587200-0-1f7ffa7bff8f06bbfbe2ace0f14b7e16&access_key=YourID
サービス側はプッシュリクエストを受信した後、auth_keyの値を抽出します。auth_keyの値を分割し、timestamp、rand、md5hashを取得します。まずtimestampが期限切れかどうかを確認できます。期限切れ時間は300sを推奨します。そして、上記のルールに基づいて暗号化文字列を組み立て、SecretKeyを使用して暗号化する必要がある文字列を組み立て、暗号化後にauth_key内のmd5hash値と比較します。同じであれば認証が成功したことを示します。
3. サービス側の認証リクエスト解析コード例
Python
Golang
import hashlib

from flask import Flask, request

app = Flask(__name__)


def get_rsp(msg, result={}, code=0):
return {
"respCode": code,
"respMsg": msg,
"result": result
}


def get_secret_key(access_key):
return "secret_key"


@app.route("/access_log/post", methods=['POST'])
def access_log():
if request.method == 'POST':
if request.content_type.startswith('application/json'):
current_time_ts, rand_num, md5hash = request.args.get("auth_key").split("-")
# リクエスト時間が有効期間内であるかどうかを判断します。
if time.time() - int(current_time_ts) > 300:
return get_rsp(msg="The request is out of time", code=-1)

access_key = request.args.get("access_key")
# access_key(SecretId)でsecret_keyを取得します。
secret_key = get_secret_key(access_key)
raw_str = "%s-%s-%s-%s" % (request.path, current_time_ts, rand_num, secret_key)
auth_md5hash = hashlib.md5(raw_str.encode("utf-8")).hexdigest()
if auth_md5hash == md5hash:
# 認証に成功しました。
if request.headers['content-encoding'] == 'gzip':
# データを解凍します。
pass
# データ処理
return get_rsp("ok")
return get_rsp(msg="Please use content_type by application/json", code=-1)
return get_rsp(msg="The request method not find, method == %s" % request.method, code=-1)

if __name__ == '__main__':
app.run(host='0.0.0.0', port=8888, debug=True)

package main

import (
"context"
"crypto/md5"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
)

func main() {
mux := http.NewServeMux()
mux.Handle("/access_log/post", &logHandler{})

server := &http.Server{
Addr: ":5000",
Handler: mux,
}

}
done := make(chan os.Signal)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-done

if err := server.Shutdown(context.Background()); err != nil {
log.Fatal("Shutdown server:", err)
}
}()

err := server.ListenAndServe()
if err != nil {
if err == http.ErrServerClosed {
log.Print("Server closed under request")
} else {
log.Fatal("Server closed unexpected")
}
}
}

type logHandler struct{}

func (*logHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
query := r.URL.Query()
authKey := query.Get("auth_key")
accessKey := query.Get("access_key")//access_keyはお客様が提供するSecretIdです。
authKeys := strings.Split(authKey, "-")
if len(authKeys) == 3 {
currentTimeTs := authKeys[0]
//タイムスタンプの有効期限を判断します。
RandNum := authKeys[1]
md5Hash := authKeys[2]
secretKey := getSecretKey(accessKey)
authStr := fmt.Sprintf("%s-%s-%s-%s", "/access_log/post", currentTimeTs, RandNum, secretKey)
data := []byte(authStr)
has := md5.Sum(data)
authMd5 := fmt.Sprintf("%x", has) //文字列に変換して比較します。
if authMd5 == md5Hash {
// todo 認証に成功しました。
if r.Header.Get("Content-Encoding") == "gzip" {
//データを解凍します。
}
//データ処理
}
} else {
//異常処理
}
}
}

// SecretKeyを取得します。
func getSecretKey(accessKey string) string {
if accessKey != "" {
// Access_key(SecretI)でSecret_Keyを取得します。
return "secret_key"
}
return ""
}



ヘルプとサポート

この記事はお役に立ちましたか?

フィードバック