Облачные вспышки - PullRequest
       58

Облачные вспышки

1 голос
/ 01 мая 2019

Я хотел добавить на свой сайт функцию, подобную этой:

Когда начинается новый сеанс, посмотрите на значения строки запроса utm_source / utm_medium, а также на реферер. В зависимости от этого отображается другой телефонный номер сайта, например, у gpp cpc, bing cpc, google органический, bing органический будет другой номер.

Количество вызовов на каждый номер должно указывать, какой источник трафика генерировал вызовы.

Проблема в том, что, поскольку мы используем clouldflare, если пользователь получает страницу из кэша, то на исходном сервере нет события session_start.

Есть ли решение, чтобы обойти это? Есть ли способ сделать это на самом Cloudflare, возможно, используя его «рабочие»?

Спасибо

1 Ответ

1 голос
/ 08 мая 2019

Работники Cloudflare могут быть использованы для этого. Рабочий сценарий сначала должен определить, какой номер телефона показывать. Это можно сделать, проверив параметры запроса, файл cookie или любой другой аспект запроса. Затем рабочий сценарий может взять исходное тело ответа (из кэша или исходного сервера) и заменить все вхождения исходного номера телефона новым номером телефона.

Вот пример рабочего сценария, который делает это. Чтобы определить, какой номер телефона показывать, он сначала проверит параметры запроса, как вы упомянули. Когда он видит параметр запроса utm_source, он также устанавливает cookie, который затем может быть проверен во всех последующих запросах, чтобы показать тот же номер телефона.

// The name of the cookie that will be used to determine which phone number to show
const cookieName = "phone_num_id";

// The list of all phone numbers to use
const phoneNumbers = [
  {
    id: "google-cpc",
    utmSource: "google",
    utmMedium: "cpc",
    phoneNumber: "222-222-2222"
  },
  {
    id: "bing-cpc",
    utmSource: "bing",
    utmMedium: "cpc",
    phoneNumber: "333-333-3333"
  }
];

// This adds a "fetch" event listener which will be called for all incoming requests
addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  // Forward the incoming request and get the original response. If Cloudflare has already cached
  // this request, this will return the cached response, otherwise it will make the request to
  // the origin
  let response = await fetch(request);

  // Check the content type of the response and fallback to an empty string
  // if there is no content-type header
  let contentType = response.headers.get("content-type") || "";

  // We're only interested in changing respones that have a content-type starting
  // with "text/html". Anything else will be returned without any modifications
  if (/^text\/html/.test(contentType)) {
    // `newPhoneNumberData` will be the new phone number to show (if any)
    let newPhoneNumberData;

    // searchParams are the query parameters for this request
    let searchParams = new URL(request.url).searchParams;

    // If the request has a `utm_source` query param, use that to determine which phone number to show
    if (searchParams.has("utm_source")) {
      let utmSource = searchParams.get("utm_source") || "";
      let utmMedium = searchParams.get("utm_medium") || "";
      // Lookup the phone number based on the `utmSource` and `utmMedium`
      newPhoneNumberData = phoneNumbers.find(
        phoneNumber =>
          phoneNumber.utmSource === utmSource &&
          phoneNumber.utmMedium === utmMedium
      );

      // If we found a match, set a cookie so that subsequent requests get the same phone number
      if (newPhoneNumberData) {
        // In order to modify the response headers, we first have to duplicate the response
        // so that it becomes mutable
        response = new Response(response.body, response);

        // Now set a cookie with the id of the new phone number to use. You should modify the properties
        // of the cookie for your use case. See this page for more information:
        // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
        response.headers.append(
          "Set-Cookie",
          `${cookieName}=${newPhoneNumberData.id}; Max-Age=2147483647`
        );
      }
    }

    // If we weren't able to determine the new phone number based on the query params, try
    // checking the cookies next
    if (!newPhoneNumberData) {
      let cookieHeader = request.headers.get("cookie") || "";

      // split each of the cookies and remove leading/trailing whitespace
      let cookies = cookieHeader.split(";").map(str => str.trim());

      // Find the phone number cookie
      let phoneNumberCookieString = cookies.find(cookieString =>
        cookieString.startsWith(`${cookieName}=`)
      );

      // If the request has the phone number cookie, use that
      if (phoneNumberCookieString) {
        // Extract the phone number id from the cookie
        const phoneNumberId = phoneNumberCookieString.split("=")[1];

        // Lookup the phone number data based on the ID
        newPhoneNumberData = phoneNumbers.find(
          phoneNumber => phoneNumber.id === phoneNumberId
        );
      }
    }

    // If we found a matching phone number to use, now we'll need to replace all occurences
    // of the original phone number with the new one before returning the response
    if (newPhoneNumberData) {
      // Get the original response body
      let responseBody = await response.text();

      // Use a regex with the `g` flag to find/replace all occurences of the original phone number.
      // This would look for a phone number like "(111)-111-1111" but you can modify this to fit
      // however your original phone number appears
      responseBody = responseBody.replace(
        /\(?111\)?[-\s]*111[-\s]*1111/g,
        newPhoneNumberData.phoneNumber
      );

      // Create a new response with the updated responseBody. We also pass the original `response` as the
      // second argument in order to copy all other properties from the original response (status, headers, etc)
      response = new Response(responseBody, response);
    }
  }

  return response;
}
...