Problema al enviar datos JSON de JQuery al método WCF REST
http-options-method (5)
Tengo problemas para obtener jquery y publicar algunos datos json en un método de descanso que tengo en mi servicio WCF.
En el lado de WCF, aquí está el contrato de operación:
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);
MyResult
y MyRequest
están marcados con todos los atributos DataContract
y DataMember
necesarios y el servicio expone el punto final WebHttp.
En el lado de JQuery, aquí está mi llamada de función:
var jsonStr = JSON.stringify(reqObj);
$.ajax({
type: "POST",
dataType: "json",
url: "http://localhost/MyService/PostSomething",
contentType: "application/json; charset=utf-8",
data: jsonStr,
success: function (html) {
alert(html);
}
});
esta solicitud nunca llega a mi método (obtengo un método 405 no permitido cada vez), y buscando en Charles la solicitud se ve así:
OPTIONS /MyService/PostSomething HTTP/1.1
Host: localhost
Cache-Control: max-age=0
Access-Control-Request-Method: POST
Origin: null
Access-Control-Request-Headers: Content-Type, Accept
Accept: */*
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
un par de cosas que es extraño sobre esto:
- el método es OPCIONES NO POST
- el tipo de contenido (en otra pestaña) muestra
text/html; charset=UTF-8
text/html; charset=UTF-8
lugar de json - los datos JSON no están en ningún lugar para ser vistos
Sin embargo, si modifico la solicitud en Charles para que sus encabezados sean similares a la solución here , entonces todo funciona:
POST /MyService/PostSomething HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: localhost
Content-Length: 152
{"Id":"", "Name":"testspot","Description":"test" }
mirando tutoriales y otras preguntas aquí otros han logrado que JQuery publique en un método WCF REST como este, y no sé qué estoy haciendo mal aquí.
oh, para poner un poco de contexto, este es un servicio WCF 4 y estoy usando JQuery 1.4.4.
Gracias,
ACTUALIZAR:
Después de leer un poco más y agradecer a Darrel por dirigirme hacia las especificaciones de dominio cruzado, logré llegar un poco más lejos haciendo algunos pequeños cambios en mi servicio, en la interfaz de servicio:
[OperationContract]
[WebInvoke(Method = "*",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);
y en la implementación, necesito verificar si las solicitudes entrantes son para OPCIONES y en ese caso devolver algunos encabezados en lugar de hacer el trabajo previsto:
if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");
return null;
}
luego se llama al método dos veces, la primera vez que el servidor devuelve un valor nulo pero agrega algunos encabezados al cliente, y luego la solicitud real se realiza con POST como método y el servidor sigue adelante y trata la solicitud normalmente.
Actualizar:
Intenta poner .svc después de MyService para que la URL lea
http://localhost/MyService.svc/PostSomething
Estuve trabajando en esto el otro día y encontré una publicación en el blog de Rick Strahl:
http://www.west-wind.com/weblog/posts/324917.aspx
Esto funciona perfectamente para mí, ¡así que pruébalo!
¡Espero que ayude! :)
En su web.config, ¿ha utilizado webhttpbinding?
solo webhttpbinding admite json.
Esto parece ser algo de Firefox para evitar llamadas de dominio cruzado. Ver http://www.petefreitag.com/item/703.cfm
La especificación para esto está aquí http://www.w3.org/TR/cors/ y después de una lectura muy breve, parece que debido a que está haciendo una llamada de dominio cruzado, se espera que su servicio implemente el método OPTIONS y devuelva algunos encabezados que permiten que se envíe el método POST.
La actualización de la pregunta que contiene una solución propuesta tiene algunos problemas: el problema es que si su entrada no es compatible con el método POST, la solicitud OPTIONS realmente no está devolviendo los encabezados permitidos correctos. Realmente no busca qué métodos están realmente permitidos en el punto final WCF; solo dice artificialmente que "POST" está permitido para cada punto final en la aplicación cuando un cliente realiza una solicitud de OPCIONES (que realmente es el cliente que pregunta qué es compatible). )
Probablemente esto esté bien, si realmente no confía en la información del método OPTIONS para devolverle una lista de métodos válida (como es el caso con algunas solicitudes CORS), pero si lo hace, deberá hacer algo como: la solución a esta pregunta: cómo manejar la solicitud AJAX JQUERY POST con autocaptura WCF
Básicamente, cada punto final debe implementar:
Webinvoke(Method="OPTIONS", UriTemplate="")
y llame a un método apropiado que cargue los encabezados adecuados a la respuesta (incluida la lista adecuada "Access-Control-Allow-Method" para ese punto final) a la persona que llama. De alguna manera apesta que los puntos finales WCF alojados no lo hagan por nosotros automáticamente, pero esta es una solución alternativa que permite un control más preciso sobre el punto final. En esa solución, los encabezados de respuesta adecuados se cargan en la implementación del punto final:
public void GetOptions()
{
// The data loaded in these headers should match whatever it is you support on the endpoint
// for your application.
// For Origin: The "*" should really be a list of valid cross site domains for better security
// For Methods: The list should be the list of support methods for the endpoint
// For Allowed Headers: The list should be the supported header for your application
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
}
Además de eso, debe establecer el indicador "CrossDomainScriptAccessEnabled" en el web.config para el punto final de enlace, o en el código para el enlace WebHttpBinding al configurar el punto final. De lo contrario, volverá a aparecer en la respuesta del encabezado cuando diga "Acceso-Control-Permitir-Origen" es "*" (o una lista de URL)
Solo publicaré una breve respuesta que me ayudó, porque otras respuestas no.
- Escenario: llamada ajax al servicio wcf.
- Causa del error: solicitud de OPCIONES automáticas de ajax antes de enviar la solicitud POST. La primera solicitud no pudo ser manejada por mi servicio.
- Solución: permita la solicitud de OPCIONES y responda a ella.
Qué necesitas hacer:
Agregue esto a web.config:
<system.webServer> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" /> <add name="Access-Control-Allow-Headers" value="Content-Type" /> </customHeaders> </httpProtocol>
Agregue esto a Global.asax.cs (si no tiene este archivo en su solución, créelo por: Agregar nuevo elemento => Visual C # => Clase de aplicación global (el nombre predeterminado es "Global.asax")):
protected void Application_BeginRequest(object sender, EventArgs e) { if (HttpContext.Current.Request.HttpMethod == "OPTIONS") HttpContext.Current.Response.End(); }