[Nodejs] domínio cruzado

insira a descrição da imagem aqui

1. O que é domínio cruzado


Domínio cruzado significa que os navegadores não podem executar scripts de outros sites. É causado pela política de mesma origem do navegador, que é uma restrição de segurança imposta pelo navegador no JavaScript. Quando um navegador solicita recursos de outro nome de domínio de uma página da Web de um nome de domínio, qualquer diferença no nome de domínio, porta ou protocolo é considerada entre domínios.

A política de mesma origem restringe os seguintes comportamentos:

Cookies, LocalStorage e IndexDB não podem ser lidos

Objetos DOM e JS não podem ser buscados

A solicitação Ajax não pode ser enviada

Aqui está um exemplo:

http://www.yyy.cn/index.html 调用 http://www.xxxyyy.cn/server.php 非跨域
http://**www.xxxyyy.cn**/index.html 调用  http://**www.xxx.cn**/server.php  跨域,主域不同
http://**abc**.xxxyyy.cn/index.html 调用  http://**def**.xxx.cn/server.php  跨域,子域名不同
http://www.xxx.cn:**8080**/index.html 调用  http://www.xxx.cn/server.php  跨域,端口不同
**https**://www.xxx.cn/index.html 调用  **http**://www.xxx.cn/server.php  跨域,协议不同

2. CORS de compartilhamento de recursos entre origens


Esta é a solução mainstream atual.

CORSÉ um padrão W3C, o nome completo é "compartilhamento de recursos entre domínios" ( Cross-origin resource sharing). Ele permite que os navegadores enviem XMLHttpRequestsolicitações para servidores de origem cruzada, superando assim a limitação de que o AJAX só pode ser usado na mesma origem.

CORSTanto o navegador quanto o suporte ao servidor são necessários. No momento, todos os navegadores suportam esta função, e o navegador IE não pode ser inferior à IE10。IE8+:IE8/9necessidade de usar XDomainRequestobjetos para apoiá-lo CORS.

Todo o CORSprocesso de comunicação é concluído automaticamente pelo navegador sem a participação do usuário. Para desenvolvedores, CORSa comunicação não é diferente da comunicação AJAX de mesma origem e o código é exatamente o mesmo. Assim que o navegador descobrir que AJAXa solicitação é de origem cruzada, ele adicionará automaticamente algumas informações de cabeçalho adicionais e, às vezes, haverá uma solicitação adicional, mas o usuário não a sentirá. Portanto, CORSa chave para realizar a comunicação é o servidor.

Basicamente, você só precisa adulterar o servidor, e o código do front-end é o mesmo de quando é da mesma fonte, ou seja, é o mesmo quando não é cross-domain.

Esse método é dividido em dois tipos de solicitações:
uma é uma solicitação simples e a outra é uma solicitação não simples. Desde que as seguintes condições sejam atendidas, é uma solicitação simples e o método de solicitação é que HEAD、POST 或者 GET,httpas informações do cabeçalho não excedam os seguintes campos:

Accept、Accept-Language 
Content-Language
Last-Event-ID
Content-Type(限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain)
为什么要分为简单请求和非简单请求,因为浏览器对这两种请求方式的处理方式是不同的。

2.1 Pedido Simples

Para solicitações simples, o navegador faz CORSa solicitação diretamente. Especificamente, é adicionar um campo nas informações do cabeçalho Origin. Veja a seguir um exemplo: quando o navegador descobre que essa AJAXsolicitação de origem cruzada é uma solicitação simples, ele adiciona automaticamente um campo às informações do cabeçalho Origin.

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0
...

OriginO campo é usado para indicar de qual fonte (protocolo + nome de domínio + porta) esta solicitação vem. Com base nesse valor, o servidor decide se concorda com a solicitação.

Se Origina fonte especificada não estiver dentro do intervalo permitido, o servidor retornará uma HTTPresposta normal. Quando o navegador descobre que as informações do cabeçalho de resposta não contêm Access-Control-Allow-Origincampos, ele sabe que algo deu errado e, portanto, lança um erro, que é capturado pela função XMLHttpRequestde retorno de chamada .onerror

Observe que esse tipo de erro não pode ser identificado pelo código de status, porque o código de status da resposta HTTP pode ser 200.

Se o nome de domínio especificado pelo Origin estiver dentro do intervalo permitido, a resposta retornada pelo servidor terá vários outros campos de cabeçalho:

  Access-Control-Allow-Origin: http://api.bob.com
  Access-Control-Allow-Credentials: true
  Access-Control-Expose-Headers: FooBar
  Content-Type: text/html; charset=utf-8

Entre as informações do cabeçalho acima, há três campos relacionados a solicitações CORS, todos começando com Access-Control-

**Access-Control-Allow-Origin *: Este campo é obrigatório. Seu valor é o valor do campo Origem no momento da solicitação, ou um, indicando que as solicitações de qualquer nome de domínio são aceitas

Access-Control-Allow-Credentials: Este campo é opcional. Seu valor é um booleano que indica se os cookies podem ser enviados. Por padrão, os cookies não são incluídos nas solicitações CORS. Se estiver definido como true, significa que o servidor permite expressamente que o Cookie possa ser incluído na solicitação e enviado ao servidor em conjunto. Este valor só pode ser definido como verdadeiro.Se o servidor não quiser que o navegador envie cookies, basta excluir este campo.

Access-Control-Expose-Headers: Este campo é opcional. CORSAo solicitar, o método XMLHttpRequestdo objeto getResponseHeader()pode obter apenas 6 campos básicos: Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma. Se você deseja obter outros campos, deve Access-Control-Expose-Headersespecificá-los nele.

atributo withCredentials

Conforme mencionado acima, as solicitações CORS não enviam cookies e informações de autenticação HTTP por padrão. Se você deseja enviar cookies para o servidor, por um lado, você precisa que o servidor concorde em especificar o campo Access-Control-Allow-Credentials.

Por outro lado, os desenvolvedores devem ativar o atributo withCredentials em solicitações AJAX.

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
    
    
    if (xhr.readyState == 4 && xhr.status == 200) {
    
    
        alert(xhr.responseText);
    }
};
//  jquery
$.ajax({
    
    
        ...
       xhrFields: {
    
    
             withCredentials: true    // 前端设置是否带cookie
       },
       crossDomain: true,  // 会让请求头中包含跨域的额外信息,但不会含cookie
        ...
});

Caso contrário, mesmo que o servidor concorde em enviar o cookie, o navegador não o enviará. Ou o servidor solicita uma configuração Cookiee o navegador não lida com isso. No entanto, se a configuração withCredentials for omitida, alguns navegadores ainda o enviarão juntos Cookie. Nesse caso, ele pode ser explicitamente fechado withCredentials.

* Deve-se observar que, se você deseja enviá-lo, Cookie,Access-Control-Allow-Originnão pode defini-lo como um asterisco e deve especificar um nome de domínio claro que seja consistente com a página da Web solicitada. **Ao mesmo tempo, Cookiea política de mesma origem ainda é seguida, apenas aqueles definidos com o nome de domínio do servidor Cookieserão carregados, outros nomes de domínio Cookienão serão carregados e os códigos originais da página da Web (origem cruzada) document.cookienão podem ser lidos em o nome de domínio do servidor Cookie.

2.2 Pedidos não simples

Uma solicitação não simples é uma solicitação que possui requisitos especiais para o servidor, como o método de solicitação é PUTou DELETE, ou Content-Typeo tipo de campo é application/json.

Para solicitações que não sejam simples , CORSserá adicionada HTTPuma solicitação de consulta antes da comunicação formal, que é chamada de solicitação de "pré-verificação" preflight( ) - o navegador primeiro pergunta ao servidor se o nome de domínio da página da Web atual está no lista de permissões do servidor e se ele pode Quais HTTPverbos e campos de cabeçalho usar. Somente quando uma resposta positiva for recebida, o navegador emitirá uma XMLHttpRequestsolicitação formal, caso contrário, um erro será relatado.

var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

Quando o navegador descobre que esta é uma solicitação não simples, ele envia automaticamente uma solicitação "preflight", solicitando ao servidor que confirme se tal solicitação é possível. Abaixo estão os cabeçalhos HTTP para esta solicitação "preflight".

  OPTIONS /cors HTTP/1.1
  Origin: http://api.bob.com
  Access-Control-Request-Method: PUT
  Access-Control-Request-Headers: X-Custom-Header
  Host: api.alice.com
  Accept-Language: en-US
  Connection: keep-alive
  User-Agent: Mozilla/5.0...

O método de solicitação usado pela solicitação "preflight" é OPTIONSpara indicar que essa solicitação é para consulta. Nas informações do cabeçalho, o campo chave serve Originpara indicar de qual origem vem a requisição. Além dos Origincampos, o cabeçalho da solicitação "preflight" contém dois campos especiais.

Access-Control-Request-Method: Este campo é obrigatório e serve para listar quais métodos HTTP serão usados ​​pela requisição CORS do navegador. O exemplo acima é PUT.

Access-Control-Request-Headers: Este campo é uma string separada por vírgula, especificando os campos de informações de cabeçalho adicionais que o navegador enviará em solicitações CORS. O exemplo acima é X-Custom-Header

Resposta à solicitação de simulação

Depois que o servidor recebe a solicitação "preflight", verifica Origin、Access-Control-Request-Method和Access-Control-Request-Headersos campos, confirma se as solicitações de origem cruzada são permitidas e, em seguida, responde

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

Na resposta HTTP acima, a chave é Access-Control-Allow-Origino campo, indicando que http://api.bob.comos dados podem ser solicitados. Este campo também pode ser definido como um asterisco, que concorda com qualquer solicitação de origem cruzada.

Se o navegador negar a solicitação "preflight", uma resposta HTTP normal será retornada, mas sem nenhum campo de cabeçalho relacionado ao CORS. Neste momento, o navegador determinará que o servidor não concorda com a solicitação de simulação, então um erro é acionado, o qual é capturado pela função onerror callback do objeto XMLHttpRequest. O console imprimirá uma mensagem de erro.

Outros campos relacionados ao CORS respondidos pelo servidor são os seguintes:

Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
  • Access-Control-Allow-Methods: Este campo é obrigatório e seu valor é uma string separada por vírgulas, indicando todos os métodos de solicitação entre domínios suportados pelo servidor. Observe que todos os métodos suportados são retornados, não apenas aquele solicitado pelo navegador. Isso é para evitar várias solicitações "preflight".
  • Access-Control-Allow-Headers: O campo é obrigatório se a solicitação do navegador Access-Control-Request-Headerso incluir. Access-Control-Allow-HeadersÉ também uma string separada por vírgula indicando todos os campos de cabeçalho suportados pelo servidor, não limitados aos solicitados pelo navegador em "preflight".
  • Access-Control-Allow-Credentials: Este campo tem o mesmo significado da solicitação simples.
  • Access-Control-Max-Age: Este campo é opcional e é usado para especificar o período de validade desta solicitação de simulação, em segundos. No resultado acima, o período de validade é de 20 dias (1.728.000 segundos), o que significa que a resposta pode ser armazenada em cache por 1.728.000 segundos (20 dias), período durante o qual outra solicitação de simulação não precisa ser enviada.

O navegador responde normalmente ao pedido

Depois que o servidor passar pela solicitação de "pré-verificação", todas as solicitações CORS normais do navegador serão iguais a uma solicitação simples e haverá um campo de cabeçalho Origin. A resposta do servidor também terá um Access-Control-Allow-Origincampo de cabeçalho.

PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

Uma solicitação CORS normal do navegador. O campo Origem das informações do cabeçalho acima é adicionado automaticamente pelo navegador. Abaixo está a resposta normal do servidor.

Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8

Access-Control-Allow-Origincampo é obrigatório para cada resposta

3. Processamento entre domínios do Nodejs


3.1 A configuração permite nomes de domínio entre domínios

  • Defina para permitir todos os nomes de domínio entre domínios
var express = require('express');
var app = express();
 
// 设置允许所有域名跨域:
app.all("*",function(req,res,next){
    
    
    //设置允许跨域的域名,*代表允许任意域名跨域
    res.header("Access-Control-Allow-Origin","*");
    //允许的header类型
    res.header("Access-Control-Allow-Headers","content-type");
    //跨域允许的请求方式 
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options')
        res.send(200);  //让options尝试请求快速结束
    else
        next();
})
  • Defina para permitir vários nomes de domínio entre domínios:
app.all("*",function(req,res,next){
    
    
  var orginList=[
      "http://www.bibi.com",
      "http://www.qq.com",
      "http://www.baidu.com"
  ]
  // 防止undefined 报错
  if(!req.headers.origin){
    
    
    return
  }
   if(orginList.includes(req.headers.origin.toLowerCase())){
    
    
    //允许的header类型
    res.header("Access-Control-Allow-Headers", "content-type");
    //跨域允许的请求方式
    res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
        //设置允许跨域的域名,*代表允许任意域名跨域
        res.header("Access-Control-Allow-Origin",req.headers.origin);
        if (req.method.toLowerCase() == 'options'){
    
    
          res.sendStatus(200);  //让options尝试请求快速结束
        }
        else{
    
    
          next();
        }
    } else {
    
    
      res.sendStatus(500)
    }
})

3.2 Usando núcleos de middleware

Instalarnpm i cors -S

Uso 1: Habilitar cross-domain para todas as fontes

const  cors = require('cors')
 app.use(cors())
 app.listen(8000, function () {
    
    
   console.log('start')
 })

Método de uso 2: configurar por condição

 var express = require('express')
 var cors = require('cors')
 var app = express()
 var whitelist = ['http://example1.com', 'http://example2.com']
//  异步配置
  var corsOptions;
 var corsOptionsDelegate = function (req, callback) {
    
    
  if (whitelist.indexOf(req.header('Origin')) !== -1) {
    
    
    corsOptions = {
    
     origin: true} //在CORS响应中反映(启用)请求的起源
  } else {
    
    
     corsOptions = {
    
     origin: false} // 拦截请求
  }
  callback(null, corsOptions) //  error  options
}

 app.all("*", cors(corsOptionsDelegate), function (req, res, next) {
    
    
 if(corsOptions.origin  === true){
    
    
    if (req.method.toLowerCase() == 'options'){
    
    
      res.sendStatus(200);  //让options尝试请求快速结束
     }
     else{
    
    
      next();
     }
   } else {
    
    
    res.sendStatus(500); //被拦截
   }
 })
  app.post('/cors',(req,res)=> {
    
    
  res.send('ok')
})
 app.listen(8000, function () {
    
    
   console.log('start')
 })

Acho que você gosta

Origin blog.csdn.net/weixin_43094619/article/details/131937904
Recomendado
Clasificación