ASP.NET Core WebApi中簡單畫素轉換跟蹤實現
畫素跟蹤雖然是最早用於跟蹤營銷轉換的方法,但它仍然被廣泛使用,像Facebook這樣的大公司仍然將其視為跟蹤網頁轉換的方法之一。
由於它的簡單性,通過畫素方法的跟蹤轉換仍然被廣泛使用。它不需要任何複雜的客戶端實現,因為它確保它將在幾乎所有可以載入影象的瀏覽器上執行。它由頁面上的一個簡單的img標記組成,該標記的src屬性指向跟蹤端點。端點從HTML頁面呈現上的影象標記發起的GET請求中接收引數,並將引數傳送到後端。作為回報,後端傳送影象內容,通常是1x1畫素透明PNG或GIF內容。
畫素的典型樣本將是這樣的:
<img src="9102 hello i love uuu" alt="" width="1" height="1" />
由於它是一個簡單的GET請求,而不是AJAX呼叫,因此您無需在後端端啟用CORS或其他任何東西,因此使用非常簡單方便。跟蹤的邏輯在伺服器端,因此我們現在將重點關注如何從請求中獲取大部分資料並使用1x1畫素影象進行響應。
所有請求的共同點是使用影象內容進行響應,因此我們將首先執行此操作。我們首先需要的是影象內容,但如果我們在每次請求時繼續從磁碟載入影象,這會損害我們的響應速度,因此可能會減慢客戶端瀏覽器中的頁面載入速度。
出於這個原因,我決定將appsettings.json中的影象內容保留為序列化的base64影象內容。此內容載入到單個位元組陣列,然後在每個控制器操作請求上提供相同的位元組陣列例項。
{ "Response": { "PixelContentBase64": "R0lGODlhAQABAPcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAABAAEAAAgEAP8FBAA7", "PixelContentType": "image/gif" }, "Logging": { "LogLevel": { "Default": "Warning" } }, "AllowedHosts": "*" }
接下來是建立一個從配置中讀取的影象內容的位元組陣列。這是在ConfigureServices方法的Startup.cs中完成的
using System; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace DotnetCorePixelSample { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSingleton<FileContentResult>(new FileContentResult( Convert.FromBase64String(this.Configuration.GetValue<String>("Response:PixelContentBase64")), this.Configuration.GetValue<String>("Response:PixelContentType") )); services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(); } } }
在載入影象的位元組陣列內容後,我們將其儲存在 FileContentResult類例項中,該例項將用於從畫素跟蹤WebAPI操作返回的響應。由於它是單音,因此每個請求都會反覆使用相同的例項,而不會在請求中新增任何其他處理。
現在還剩下什麼,因為我們從Startup中配置的DI注入的內容是收集資料。這是通過訪問QueryString引數和Header值在控制器操作中完成的,這些引數是每個請求的一部分。
由於我們不需要等待資料儲存完成,我們可以將其包裝在Task中並立即返回影象響應。這是一個性能改進,可能導致整個頁面在客戶端執行不良。
using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Primitives; namespace DotnetCorePixelSample.Controllers { [Route("[controller]")] [ApiController] public class TrackController : ControllerBase { readonly FileContentResult pixelResponse; public TrackController(FileContentResult pixelResponse) { this.pixelResponse = pixelResponse; } public IActionResult get() { var parameters = Request.Query.Keys.ToDictionary(k => k, k => Request.Query[k]); var headers = Request.Headers.Keys.ToDictionary(k => k, k => Request.Query[k]); Task.Factory.StartNew((data) => { var dataDictionary = data as IDictionary<string, StringValues>; }, parameters.Union(headers).ToDictionary(k=>k.Key, v=>v.Value)).ConfigureAwait(false); return pixelResponse; } } }
儲存資料與此邏輯無關,您可以使用任何儲存來儲存收集的資料。