Как работать с CORS для AMP

У меня есть страница, на которой используется amp-list для динамического перечисления продуктов с использованием файла JSON. Моя структура каталогов выглядит следующим образом: *root*/amp/product-name/, а затем в каталоге product-name у меня есть index.html с AMP HTML и products.json, который содержит данные о продукте, которые я отображаю на странице. Если я захожу на страницу напрямую, все работает как положено: https://example.com/amp/product-name/

Проблема возникает, когда я захожу с CDN ampproject.org.

Вот настоящая страница. Если вы посетите консоль, вы увидите, что есть ошибка CORS. Как мне с этим справиться? В документации неясно, как именно работать, просто очень расплывчатый обзор, поэтому для новичков это не имеет смысла для меня, и я не могу просто интуитивно понять, как это сделать. Я знаю, что мне нужен какой-то обработчик запросов, который я частично создал, скопировав код из собственного app.js AMP, на который они ссылаются в своей документации. В элементе amp-list я ранее указывал src непосредственно на файл JSON, но теперь я вижу, что мне нужно указать обработчик (например, файл JS), а затем обработчик установил заголовок запроса, а затем вывести правильный JSON.

Вот что у меня есть для обработчика запросов:

/**
 * @param {string} url
 * @param {string} param
 * @param {*} value
 * @return {string}
 */
function addQueryParam(url, param, value) {
  const paramValue = encodeURIComponent(param) + '=' + encodeURIComponent(value);
  if (!url.includes('?')) {
    url += '?' + paramValue;
  } else {
    url += '&' + paramValue;
  }
  return url;
}

function enableCors(req, res, origin, opt_exposeHeaders) {
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  res.setHeader('Access-Control-Allow-Origin', origin);
  res.setHeader('Access-Control-Allow-Origin', 'https://www-perfectimprints-com.cdn.ampproject.org');
  res.setHeader('Access-Control-Expose-Headers', ['AMP-Access-Control-Allow-Source-Origin'].concat(opt_exposeHeaders || []).join(', '));
  if (req.query.__amp_source_origin) {
    res.setHeader('AMP-Access-Control-Allow-Source-Origin', req.query.__amp_source_origin);
  }
}

function assertCors(req, res, opt_validMethods, opt_exposeHeaders, opt_ignoreMissingSourceOrigin) {
  // Allow disable CORS check (iframe fixtures have origin 'about:srcdoc').
  if (req.query.cors == '0') {
    return;
  }
  const validMethods = opt_validMethods || ['GET', 'POST', 'OPTIONS'];
  const invalidMethod = req.method + ' method is not allowed. Use POST.';
  const invalidOrigin = 'Origin header is invalid.';
  const invalidSourceOrigin = '__amp_source_origin parameter is invalid.';
  const unauthorized = 'Unauthorized Request';
  let origin;
  if (validMethods.indexOf(req.method) == -1) {
    res.statusCode = 405;
    res.end(JSON.stringify({
      message: invalidMethod
    }));
    throw invalidMethod;
  }
  if (req.headers.origin) {
    origin = req.headers.origin;
    if (!ORIGIN_REGEX.test(req.headers.origin)) {
      res.statusCode = 500;
      res.end(JSON.stringify({
        message: invalidOrigin
      }));
      throw invalidOrigin;
    }
    if (!opt_ignoreMissingSourceOrigin && !SOURCE_ORIGIN_REGEX.test(req.query.__amp_source_origin)) {
      res.statusCode = 500;
      res.end(JSON.stringify({
        message: invalidSourceOrigin
      }));
      throw invalidSourceOrigin;
    }
  } else if (req.headers['amp-same-origin'] == 'true') {
    origin = getUrlPrefix(req);
  } else {
    res.statusCode = 401;
    res.end(JSON.stringify({
      message: unauthorized
    }));
    throw unauthorized;
  }
  enableCors(req, res, origin, opt_exposeHeaders);
}

А вот что я использую для HTML.

<amp-list credentials = "include" width = "auto" height = "1500" layout = "fixed-height" src = "https://perfectimprints.com/amp/handle-amp-requests.js" class = "m1">
      <template type = "amp-mustache" id = "amp-template-id">
        <div class = "product" style = "padding-top: 1em;">
          <a class = "wrapper-link" href = "{{ link }}">
            <amp-img alt = "{{ title }}" width = "1000" height = "1000" src = "{{ src }}" layout = "responsive"></amp-img>
            <h3 class = "product-name text-centered">
              {{title}}
            </h3>
            <h4 class = "text-centered sku margin-minus-1">{{ sku }}</h4>
            <div class = "text-centered get-price">
              <a class = "text-centered get-price-link" href = "{{ link }}">Get pricing now</a>
            </div>
          </a>
        </div>
      </template>
      <div overflow role = "button" aria-label = "Show more">
        Show more
       </div>
    </amp-list>

https://www-perfectimprints-com.cdn.ampproject.org/c/s/www.perfectimprints.com/amp/trick-or-treat-bags/index.html

Src в amp-list предназначен только для исходного файла JSON, который содержит информацию для ваших тегов усов, а не для JS, как вы сейчас установили. Заголовки CORS должны быть указаны в информации заголовка страницы. Лучше всего, в зависимости от настроек вашего сервера (Apache или Nginx), установить заголовки CORS в файле htacess (Apache) или conf (Nginx).

Craig Scott 24.08.2018 20:20

Хорошо, как бы ты это сделал? Я пробовал использовать .htaccess, но он не работает.

Patrick 24.08.2018 20:22
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
2
3 759
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Предполагая, что вы находитесь на сервере Apache, вы можете установить заголовок CORS в файле htaccess следующим образом:

Header set Access-Control-Allow-Origin "https://www-perfectimprints-com.cdn.ampproject.org"
Header set Access-Control-Allow-Origin "https://www-perfectimprints-com.amp.cloudflare.com"

Затем убедитесь, что ваш файл htaccess загружен в каталог, содержащий HTML-код вашего веб-сайта. Вот как это устроено на сайте, которым я управляю, и у нас все работает.

Я использую сервер Apache, и я пробовал это, но по какой-то причине он не работает. Думаю, это могло быть из-за кеширования cdn.ampproject.org. Я здесь в своем уме.

Patrick 24.08.2018 21:45

Только что проверили ваш сайт, и похоже, что многие ваши ошибки исправлены? Единственная проблема, на которую он сейчас указывает, - это отсутствие SSL в вашем amp-list src. Как вы сказали, ссылка AMP, скорее всего, содержит кешированную версию. Ваша стандартная ссылка говорит, что AMP действительна, просто жалуется на отсутствие SSL в amp-list src. В настоящее время наиболее авторитетные хостинг-провайдеры предлагают бесплатный SSL-сервис через cPanel. Если у вас нет, Let's Encrypt бесплатен: letsencrypt.org.

Craig Scott 25.08.2018 04:47

Привет, Крейг, спасибо, что заглянули. Я полностью собирался вернуться и опубликовать, что нашел решение. Я добавил то, что у вас было выше, в свой .htaccess, а затем добавил остальные вещи, на которые он жаловался, в консоль JS одну за другой, пока он не перестал жаловаться. Спасибо за вашу помощь (еще раз! Вы уже помогали мне раньше). Что касается SSL, это должно быть потому, что я ссылался на источник, например src = "products.json", а не на более прямую ссылку, например src = "https://example.com/amp/product-name/products.json". Спасибо за подсказку, в понедельник обновлю до нужной ссылки.

Patrick 25.08.2018 06:09
Ответ принят как подходящий

Это было решение, которое сработало для меня.

Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Origin "https://example-com.cdn.ampproject.org"
Header set Access-Control-Allow-Source-Origin "https://example.com"
Header set Access-Control-Expose-Headers AMP-Access-Control-Allow-Source-Origin
Header set AMP-Access-Control-Allow-Source-Origin "https://example.com"

Спасибо @Craig Scott за подсказку, которая помогла мне решить.

Горе бедной неопытной душе, занимающейся AMP-страницами.

Другие вопросы по теме