Ошибка предварительного запуска CORS в облаке Google в нулевых экземплярах

# #cors #google-cloud-run #keystonejs

Вопрос:

Я пытаюсь запустить серверную часть keystonejs на основе Nodejs в google cloud run. И я позволил сервису уменьшиться до нуля экземпляров.

Если я какое-то время не подключался к интерфейсу, я сталкиваюсь с ошибкой предполетной подготовки CORS

 Access to fetch at 'https://***/admin/api' from origin 'https:/***.de' has been blocked by CORS 
policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow- 
Origin' header is present on the requested resource. If an opaque response serves your needs, set the 
request's mode to 'no-cors' to fetch the resource with CORS disabled.
 

Но если я обновлюсь через несколько секунд, сайт будет работать так, как ожидалось.
Обновления в ближайшие минуты также хорошо работают и на других устройствах.

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

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

текущие настройки cors

 cors: {
    origin: "https://xyz.de",
    credentials: true,
    methods: ["GET", "PUT", "POST", "OPTIONS", "DELETE", "PATCH", "HEAD"],
    maxAge: 7200,
  },
 

добавлены скриншоты из инструментов разработки chrome
сеть при сбое нагрузки введите описание изображения здесь

деталь заголовка 1 введите описание изображения здесь

деталь заголовка 2 введите описание изображения здесь

введите описание изображения здесь

завиток X при неудачном запуске

 ml@SurfaceBook3-ML:~$ curl -X OPTIONS https://roadmaptestbackend-bchawrp2qq-ew.a.run.app/admin/api
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>KeystoneJS</title>
    <style type="text/css">
      html,
      body {
        height: 100vh;
      }
      body {
        align-items: center;
        background-color: #fafbfc;
        color: #172b4d;
        display: flex;
        flex-direction: column;
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial,
          sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
        font-size: 15px;
        justify-content: center;
        letter-spacing: -0.005em;
        margin: 0;
        padding: 0;
        text-decoration-skip: ink;
        text-rendering: optimizeLegibility;
        -ms-overflow-style: -ms-autohiding-scrollbar;
        -moz-font-feature-settings: 'liga' on;
        -moz-osx-font-smoothing: grayscale;
        -webkit-font-smoothing: antialiased;
      }
      h1 {
        font-weight: 300;
        margin-bottom: 0.66em;
        margin-top: 0;
      }
      p {
        color: #6c798f;
      }
      .container {
        margin-top: -4vh;
        padding-left: 1em;
        padding-right: 1em;
        text-align: center;
      }
      /* Loading spinner from loading.io/css */
      .loading-spinner {
        display: inline-block;
        height: 64px;
        position: relative;
        width: 64px;
      }
      .loading-spinner > div {
        animation-timing-function: cubic-bezier(0, 1, 1, 0);
        background: #172b4d;
        border-radius: 50%;
        height: 11px;
        position: absolute;
        top: 27px;
        width: 11px;
      }
      .loading-spinner div:nth-child(1) {
        animation: loading-spinner1 0.6s infinite;
        left: 6px;
      }
      .loading-spinner div:nth-child(2) {
        animation: loading-spinner2 0.6s infinite;
        left: 6px;
      }
      .loading-spinner div:nth-child(3) {
        animation: loading-spinner2 0.6s infinite;
        left: 26px;
      }
      .loading-spinner div:nth-child(4) {
        animation: loading-spinner3 0.6s infinite;
        left: 45px;
      }
      @keyframes loading-spinner1 {
        0% {
          opacity: 0;
          transform: scale(0);
        }
        100% {
          opacity: 1;
          transform: scale(1);
        }
      }
      @keyframes loading-spinner3 {
        0% {
          opacity: 1;
          transform: scale(1);
        }
        100% {
          opacity: 0;
          transform: scale(0);
        }
      }
      @keyframes loading-spinner2 {
        0% {
          transform: translate(0, 0);
        }
        100% {
          transform: translate(19px, 0);
        }
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="loading-spinner">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
      </div>

      <h1>Keystone is <span id="status">loading...</span></h1>
      <p>This page will reload when the server is ready</p>
    </div>
    <script>
      const statusEl = document.querySelector('#status');
      let ready = false;

      function onReady() {
        statusEl.innerHTML = 'ready!';
        ready = true;
        location.reload(true);
      }

      function checkAndSetStatus() {
        let cancelled = false;
        fetch('/', { headers: { Accept: 'application/json' } })
          .then(result => result.json())
          .catch(error => {
            // We can get back an error "Cannot parse JSON" when a HTML
            // response is returned, so we assume the server is ready
            onReady();
          })
          .then(({ loading, status } = {}) => {
            if (!loading) {
              onReady();
              return;
            }
            if (cancelled) {
              return;
            }
            switch (status) {
              case 'init-keystone': {
                statusEl.innerHTML = 'initialising...';
                break;
              }
              case 'db-connect': {
                statusEl.innerHTML = 'connecting to the database...';
                break;
              }
              case 'start-server':
              default: {
                statusEl.innerHTML = 'loading...';
                break;
              }
            }
          });
        return () => {
          cancelled = true;
        };
      }

      let cancelLastCall = checkAndSetStatus();
      const interval = setInterval(() => {
        cancelLastCall();
        if (ready) {
          clearInterval(interval);
          return;
        }
        cancelLastCall = checkAndSetStatus();
      }, 500);
    </script>
  </body>
</html> 

Комментарии:

1. У вас есть какая-либо информация о выполняемом HTTP-запросе CORS? Я пытаюсь воспроизвести это, но пока не смог.

2. Привет @JamesWard рад видеть, что вы пытаетесь мне помочь, потому что я уже 2 недели борюсь с этой проблемой 🙂 Я добавил скриншоты сети инструментов разработчика во время неудачного запроса в свой пост. Это подразумевалось, когда вы говорили о HTTP-запросе CORS? Дополнительная информация: серверная часть: keystonejs на базе nodejs 5 интерфейс: взаимодействие с клиентом apollo

3. Странно, что запрос ПАРАМЕТРОВ возвращает HTML-содержимое и ответ 200. Что находится в теле ответа, когда это происходит?

4. извините, но где я могу найти информацию об этом теле? в области сети, куда я скопировал заголовок, на вкладке «Ответ» написано: «Не удалось загрузить данные ответа» для всех записей » api » при неудачной загрузке, если вы хотите проверить самостоятельно, см.: modernworkplacebau.de

5. Хмм. Возможно, вам придется завить его, когда он сломается: curl -X OPTIONS your-url