Había desarrollado una aplicación PhoneGap que ahora se está transformando en un sitio web móvil. Todo funciona sin problemas, además de un pequeño error. Utilizo cierta API de terceros a través de una solicitud POST, que funciona bien en la aplicación, pero falla en la versión del sitio web móvil.
Después de una mirada más cercana, parece que AngularJS (supongo que el navegador en realidad) está enviando primero una solicitud de OPCIONES. Hoy aprendí mucho sobre CORS, pero parece que no puedo averiguar cómo desactivarlo por completo. No tengo acceso a esa API (por lo que los cambios en ese lado son imposibles), pero agregaron el dominio en el que estoy trabajando a su encabezado Access-Control-Allow-Origin.
Este es el código del que estoy hablando:
var request = {
language: 'fr',
barcodes: [
{
barcode: 'somebarcode',
description: 'Description goes here'
}
]
};
}
var config = {
headers: {
'Cache-Control': 'no-cache',
'Content-Type': 'application/json'
}
};
$http.post('http://somedomain.be/trackinginfo', request, config).success(function(data, status) {
callback(undefined, data);
}).error(function(data, status) {
var err = new Error('Error message');
err.status = status;
callback(err);
});
¿Cómo puedo evitar que el navegador (o AngularJS) envíe esa solicitud de OPCIONES y simplemente salte a la solicitud POST real? Estoy usando AngularJS 1.2.0.
Gracias por adelantado.
Como dijo Ray, puede detenerlo modificando el encabezado de contenido como:
$http.defaults.headers.post["Content-Type"] = "text/plain";
Por ejemplo -
angular.module('myApp').factory('User', ['$resource','$http', function($resource,$http){ $http.defaults.headers.post["Content-Type"] = "text/plain"; return $resource(API_ENGINE_URL+'user/:userId', {}, { query: {method:'GET', params:{userId:'users'}, isArray:true}, getLoggedIn:{method:'GET'} }); }]);
O directamente a una llamada -
var req = { method: 'POST', url: 'http://example.com', headers: { 'Content-Type': 'text/plain' }, data: { test: 'test' } } $http(req).then(function(){...}, function(){...});
Esto no enviará ninguna solicitud de opción previa al vuelo.
NOTA: La solicitud no debe tener ningún parámetro de encabezado personalizado. Si el encabezado de la solicitud contiene un encabezado personalizado, el navegador realizará una solicitud previa al vuelo, no puede evitarlo.
fuente
$http
?GET
y un encabezado adicionalAuthorization
. Pero aún enviando la verificación previa.Al realizar ciertos tipos de solicitudes AJAX entre dominios, los navegadores modernos que admiten CORS insertarán una solicitud adicional de "verificación previa" para determinar si tienen permiso para realizar la acción. De consulta de ejemplo:
$http.get( ‘https://example.com/api/v1/users/’ +userId, {params:{ apiKey:’34d1e55e4b02e56a67b0b66’ } } );
Como resultado de este fragmento podemos ver que a la dirección se le enviaron dos solicitudes (OPTIONS y GET). La respuesta del servidor incluye encabezados que confirman la permisibilidad de la consulta GET. Si su servidor no está configurado para procesar una solicitud de OPCIONES correctamente, las solicitudes de cliente fallarán. Por ejemplo:
Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: accept, origin, x-requested-with, content-type Access-Control-Allow-Methods: DELETE Access-Control-Allow-Methods: OPTIONS Access-Control-Allow-Methods: PUT Access-Control-Allow-Methods: GET Access-Control-Allow-Methods: POST Access-Control-Allow-Orgin: * Access-Control-Max-Age: 172800 Allow: PUT Allow: OPTIONS Allow: POST Allow: DELETE Allow: GET
fuente
Creo que la mejor manera es verificar si la solicitud es del tipo "OPCIONES" y devolver 200 de middleware. Funcionó para mí.
express.use('*',(req,res,next) =>{ if (req.method == "OPTIONS") { res.status(200); res.send(); }else{ next(); } });
fuente
Preflight es una función de seguridad web implementada por el navegador. Para Chrome, puede deshabilitar toda la seguridad web agregando la marca --disable-web-security.
Por ejemplo: "C: \ Archivos de programa \ Google \ Chrome \ Application \ chrome.exe" --disable-web-security --user-data-dir = "C: \ newChromeSettingsWithoutSecurity". Primero puede crear un nuevo acceso directo de Chrome, ir a sus propiedades y cambiar el objetivo como se indicó anteriormente. ¡Esto debería ayudar!
fuente
establecer el tipo de contenido en indefinido haría que javascript pasara los datos del encabezado tal como están, y sobre escribir las configuraciones de encabezado angular $ httpProvider predeterminadas. Documentación de Angular $ http
$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure);
fuente