1. 程式人生 > >ASP.NET Core WebApi中簡單畫素轉換跟蹤實現

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影象內容。此內容載入到單個位元組陣列,然後在每個控制器操作請求上提供相同的位元組陣列例項。

因此,讓我們首先將1x1pixel透明影象儲存在配置中。

{
  "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;
        }
    }
}

儲存資料與此邏輯無關,您可以使用任何儲存來儲存收集的資料。