Google AMP - Cors

Neste capítulo, tentaremos entender o CORS em AMP. Antes de nos aprofundarmos nos detalhes, vamos entender os fundamentos do CORS e como ele é útil.

O que é CORS?

CORS significa Cross Origin Resource Sharing. CORS é um processo que precisa de dados extras do cabeçalho HTTP para informar ao navegador se a solicitação feita ao url pela página da web em execução, digamos, de origem xyz.com deve receber permissão para acessar os dados do url solicitado. Fazemos muitas solicitações de http da página da web e, para isso, precisamos ter o CORS em funcionamento para obter os dados necessários.

Quando fazemos uma solicitação http para um servidor diferente do host, a chamamos de solicitação de origem cruzada, o que significa que o domínio, o protocolo e a porta são diferentes da origem do host. Nesse caso, deve haver uma permissão da url solicitada para acessar os dados; significa que a solicitação GET / PUT / POST / DELETE foi feita.

Esses dados adicionais estão disponíveis no cabeçalho do navegador para a chamada de solicitação http feita. Esta etapa de permissão é basicamente necessária por motivos de segurança, de modo que nenhuma página da web pode criar ou obter dados de outro domínio sem a permissão necessária.

O cabeçalho do navegador deve ter detalhes como Access-Control-Allow-Origin que pode ter valores conforme mostrado abaixo -

Access-Control-Allow-Origin : *

Ter o valor * para o cabeçalho da URL de solicitação significa que ele informa aos navegadores para permitir a solicitação de dados de qualquer origem para acessar o recurso.

Access-Control-Allow-Origin: https://www.example.com

Ter o valor acima informa ao navegador que a solicitação feita a partir da página www.example.com só terá permissão para obter os dados do url solicitado.

A configuração do servidor para CORS deve ser feita tendo em mente como os dados que são compartilhados serão usados. Dependendo disso, os cabeçalhos necessários devem ser configurados no lado do servidor.

Agora que sabemos o que é CORS, vamos dar mais um passo em frente. No caso de amp, temos componentes como amp-form, amp-list, que usa endpoints http para carregar dados dinamicamente.

No caso de páginas de amp, mesmo que a solicitação http seja feita da mesma origem, precisamos ter a configuração CORS em vigor. Questões surgem aqui - por que devemos ter CORS ativado, mesmo se a solicitação e a resposta virão da mesma origem. Tecnicamente, não precisamos do CORS habilitado nesse caso porque estamos solicitando e exibindo dados para o mesmo domínio, origem, etc.

O Amp tem um recurso chamado cache, que é adicionado para levar os dados mais rapidamente ao usuário que acessa a página. Caso o usuário já tenha visitado a página, os dados serão armazenados em cache no google cdn o próximo usuário obterá os dados servidos do cache.

Os dados são armazenados na extremidade do amplificador, que agora possui um domínio diferente. Quando o usuário clica em qualquer botão para obter novos dados, o url do cache do amp é comparado com o domínio da página da web para obter os novos dados. Agora, se o CORS não estiver habilitado, pois lida com o url em cache do amp e o domínio da página da web, a solicitação não será válida e falhará para a permissão do CORS. Este é o motivo pelo qual precisamos ter CORS habilitado, mesmo para a mesma origem no caso de páginas de amplificador.

Um exemplo prático de trabalho com formulários com CORS ativado é mostrado aqui -

<!doctype html>
<html amp lang = "en">
   <head>
      <meta charset = "utf-8">
      <script async src = "https://cdn.ampproject.org/v0.js">
      </script>
      <title>Google AMP - Form</title>
      <link rel = "canonical" href = "ampform.html">
      <meta name = "viewport" content = "width = device-width,
      minimum-scale = 1,initial-scale = 1">
      
      <style amp-boilerplate>
         body{
            -webkit-animation:
            -amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:
            -amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:
            -amp-start 8s steps(1,end) 0s 1 normal both;animation:
            -amp-start 8s steps(1,end) 0s 1 normal both
         }
         @-webkit-keyframes 
         -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes 
         -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes 
         -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes 
         -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes 
         -amp-start{from{visibility:hidden}to{visibility:visible}}
      </style>
      <noscript>
         <style amp-boilerplate>
            body{
               -webkit-animation:none;
               -moz-animation:none;
               -ms-animation:none;
               animation:none}
         </style>
      </noscript>
      <script async custom-element = "amp-form" 
         src = "https://cdn.ampproject.org/v0/amp-form-0.1.js">
      </script>
      <script async custom-template = "amp-mustache" 
         src = "https://cdn.ampproject.org/v0/amp-mustache-0.2.js">
      </script>
      <style amp-custom>
         form.amp-form-submit-success [submit-success],
         form.amp-form-submit-error [submit-error]{
            margin-top: 16px;
         }
         form.amp-form-submit-success [submit-success] {
            color: white;
            background-color:gray;
         }
         form.amp-form-submit-error [submit-error] {
            color: red;
         }
         form.amp-form-submit-success.hide-inputs > input {
            display: none;
         }
      </style>
   </head>
   <body>
      <h3>Google AMP - Form</h3>
      <form 
         method = "post" 
         class = "p2" 
         action-xhr = "submitform.php" 
         target = "_top">
            <p>AMP - Form Example</p>
            <div>
               <input 
                  type = "text" 
                  name = "name" 
                  placeholder = "Enter Name" required>
               <br/>
               <br/>
               <input 
                  type = "email" 
                  name = "email" 
                  placeholder = "Enter Email" 
                  required>
               <br/>
               <br/>
            </div>
            <input type = "submit" value = "Submit">
            <div submit-success>
               <template type = "amp-mustache">
                  Form Submitted! Thanks {{name}}.
               </template>
            </div>
            <div submit-error>
               <template type = "amp-mustache">
                  Error! {{name}}, please try again.
               </template>
            </div>
      </form>
   </body>
</html>

submitform.php

<?php
   if(!empty($_POST)){
      $domain_url = (isset($_SERVER['HTTPS']) ? "https" : "http") . 
         "://$_SERVER[HTTP_HOST]";
      header("Content-type: application/json");
      header("AMP-Access-Control-Allow-Source-Origin: " . $domain_url);
      header("Access-Control-Expose-Headers: 
         AMP-Access-Control-Allow-Source-Origin");
      $myJSON = json_encode($_POST);
      echo $myJSON;
   }
?>

Resultado

Os detalhes dos cabeçalhos de resposta adicionados a submitform.php -

Para que o formulário funcione, precisamos adicionar cabeçalhos como access-control-expose-headers com o valor AMP-Access-Control-Allow-Source-Origin e amp-access-control-allow-source-origin - http://localhost:8080.

Aqui estamos usando o arquivo php e apache é o servidor usado. No arquivo php, adicionamos os cabeçalhos necessários conforme mostrado abaixo -

<?php
   if(!empty($_POST)){
      $domain_url = (isset($_SERVER['HTTPS']) ? "https" : "http") .
         "://$_SERVER[HTTP_HOST]";
      header("Content-type: application/json");
      header("AMP-Access-Control-Allow-Source-Origin: " . $domain_url);
      header("Access-Control-Expose-Headers: 
         AMP-Access-Control-Allow-Source-Origin");
      $myJSON = json_encode($_POST);
      echo $myJSON;
   }
?>

Quando os cabeçalhos necessários são adicionados, a origem http://localhost:8080 terá permissão para interagir e obter os dados de volta.,