zoukankan      html  css  js  c++  java
  • (转)jquery跨域调用webService,以及解决跨域情况下只能返回XMl格式数据的问题

    http://lu.9efish.com/blog/jquery-cross-domain-call-asp.net-web-service原文地址

    网上有很多文章介绍如何使用jquery调用web service,在同一个域里都没什么问题 运行都是良好的。但在实际的应用中 我们既然已经部署了web 
    service当然是希望有更多的外部的客户端调用的。而其中就有其他域里的javascript调用web service获取信息的需求。

    在网上找了一下 也是有文章介绍的 文章1 文章2 我的解决思路基本上就是从这两篇文章里来的。但使用这两篇文章的时候也碰到了一点问题 
    所以我使用自己的方式修改了一下。jquery跨域调用asp.net web service,首先要了解的一个概念是 JSONP 链接里有介绍。

    总之为了安全 少些网络攻击 钓鱼等,跨域访问是要受到严格限制的。比如 
    不能跨域使用POST,JQuery调用也需要使用JSONP来传输数据。但由于asp.net 3.5的web 
    service不内置支持jsonp,碰上很多问题。下面列出我已经测试正确的方法。

    首先看客户端JQuery的代码:

    -------------------------------------------------------------------------------------------------------------------

    <script type="text/javascript">
        $(function () {
            $.ajax({
                url: 'http://myserver/Web%20Service/Search.asmx/Search?format=jsonp',
                data: {'from': 'Oslo', 'to': 'Hamburg', 'type': 1 },
                dataType: "jsonp",
                type: "GET",
                success: OnSuccess,
                error: OnError
            });
        });

        function OnSuccess(jsondata) {
        }
        function OnError (xhr, msg){
        }
    </script>

    ------------------------------------------------------------------------------------------------------------------

    代码里Jquery ajax的调用使用的type为 "GET", 
    所以就算在这里指定了contentType也是没有用的,这就是悲剧的源头。上面的代码里要注意的一个地方是在调用的URL里我们添加了一个参数format=jsonp, 
    这个后面会使用到。然后再是web service的代码:

    ----------------------------------------------------------------------------------------------------------------

    [WebService(Namespace = "http://temp.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.Web.Script.Services.ScriptService]
    public class Search : System.Web.Services.WebService {
     [WebMethod(EnableSession=true)]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json,UseHttpGet=true)]
     public string Search(string from,string to,int type) {
       SearchResult result= new SearchResult();
    ......
    
     return result.toJSON(); }}

    -------------------------------------------------------------------------------------------------------------------

    根据上面的代码 再在web.config里加上下面一句话

    ------------------------------------------------------------------------------------------------------------------

    <system.web>   
    
    .......
    
        <webServices>
          <protocols>
            <add name="HttpGet"/>
            <add name="HttpPost"/>
          </protocols>
        </webServices>
     </system.web>
    

    -----------------------------------------------------------------------------------------------------------------

    到这里 如果你跟踪代码执行的话 其实web service的代码调用已经是成功了的,但你是得不到返回值的,如果用firebug查看一下
    会有一个错误出现,是jquery解析返回值的时候出错的信息。问题是这样出现的 在web service返回值时 其实没有返回JSONP格式
    而是把你生成的string返回值包到了一个xml格式里。在上面提到的两篇文章里
    作者都使用了一个HttpModule来拦截Request请求,强制给Request.ContentType赋值为"application/json;
    charset=utf-8", 这样web service返回值也是使用json格式返回 然后再在HttpModule包上一个JSONP的外衣也算是大功告成。
    但我在实际使用时碰上了一个问题,就是当Request.ContentType="application/json; charset=utf-8"
    后,解析我Jquery里Data的参数出现了错误,而上面的文章里也是使用了对URL参数进行进一步的包装之后 才让asp.net web
    service解析成功。而我为了使客户端精良的简单使用了另外一个办法就是在web service返回的xml格式的结果时
    进行重新包装。当然也是需要添加一个IHttpModule的 代码可以在这里下载

    通过这样的改造 jquery就能正确解析出结果了。下面再给出那个.toJSON的代码

    -----------------------------------------------------------------------------------------------------------------

    public static class Extention
    {
        public static string toJSON(this object obj)
        {
            string jsonstring = new JavaScriptSerializer().Serialize(obj);
            return jsonstring;
         }
    }

    -----------------------------------------------------------------------------------------------------------------

    以上代码 实际能用IE8,firefox测试

    ==================================================================================

    下面加个demo:

    js:

        <script src="../js/jquery-1.6.4.min.js" type="text/javascript"></script>

    <script type="text/javascript">
    $(function() {
    $.ajax({
    type: "GET",
    cache: false,
    url: "http://localhost:7067/WebService/Service.asmx/GetJsonp?format=jsonp",
    //url: "../WebService1.asmx/GetJsonp",
    data: { value: 'GET 参数', secretCode: '111111111' },
    dataType: "jsonp",
    jsonp: "callback",
    jsonpCallback: "showRs"
    });


    });
    function showRs(_rs) {
    alert(_rs.msg);
    }
    </script>

    WS:

        [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true)]
    public string GetJsonp(string value, string secretCode)
    {
    string jsonpcallback = HttpContext.Current.Request.QueryString["callback"];
    return "{\"msg\":\"" + value + secretCode + "\"}";
    //return jsonpcallback + "('" + value + secretCode + "')";
    }


    下面是那个Module代码,以防链接失效:

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.IO;
    using System.Text;
    using System.Xml.Linq;
    /// <summary>
    /// 解决ajax跨域调用web service返回结果需要修改
    /// web service不认jsonp的格式 会自动返回xml 使客户端 如jquery等解析出错
    /// </summary>
    public class JsonpHttpModule : IHttpModule
    {
    private const string JSON_CONTENT_TYPE = "application/json; charset=utf-8";

    #region IHttpModule Members
    public void Dispose()
    {
    }

    public void Init(HttpApplication app)
    {
    app.BeginRequest += OnBeginRequest;
    app.ReleaseRequestState += OnReleaseRequestState;
    }
    #endregion
    bool _Apply(HttpRequest request)
    {
    if (!request.Url.AbsolutePath.Contains(".asmx")) return false;
    if ("jsonp" != request.QueryString.Get("format")) return false;
    return true;
    }

    public void OnBeginRequest(object sender, EventArgs e)
    {
    //HttpApplication app = (HttpApplication)sender;

    //if (!_Apply(app.Context.Request)) return;

    //// correct content type of request
    //if (string.IsNullOrEmpty(app.Context.Request.ContentType))
    //{
    // app.Context.Request.ContentType = JSON_CONTENT_TYPE;
    //}

    }

    public void OnReleaseRequestState(object sender, EventArgs e)
    {
    HttpApplication app = (HttpApplication)sender;
    if (!_Apply(app.Context.Request)) return;
    // apply response filter to conform to JSONP
    //由于使用Http Get 默认的解析方法 在返回内容是会使用xml格式 这里把他的xml外衣脱掉
    app.Context.Response.Filter =
    new JsonResponseFilter(app.Context.Response.Filter);

    }
    }

    public class JsonResponseFilter : Stream
    {
    private readonly Stream _responseStream;
    private long _position;

    public JsonResponseFilter(Stream responseStream)
    {
    _responseStream = responseStream;
    }

    public override bool CanRead { get { return true; } }

    public override bool CanSeek { get { return true; } }

    public override bool CanWrite { get { return true; } }

    public override long Length { get { return 0; } }

    public override long Position { get { return _position; } set { _position = value; } }

    public override void Write(byte[] buffer, int offset, int count)
    {
    string strBuffer = Encoding.UTF8.GetString(buffer, offset, count);
    strBuffer = AppendJsonpCallback(strBuffer, HttpContext.Current.Request);
    byte[] data = Encoding.UTF8.GetBytes(strBuffer);
    _responseStream.Write(data, 0, data.Length);
    }

    private string AppendJsonpCallback(string strBuffer, HttpRequest request)
    {
    try
    {
    XDocument x = XDocument.Parse(strBuffer);
    return request.Params["callback"] + "(" + x.Descendants ().FirstOrDefault ().Value + ");";
    }
    catch
    {
    return strBuffer;
    }
    }

    public override void Close()
    {
    _responseStream.Close();
    }

    public override void Flush()
    {
    _responseStream.Flush();
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
    return _responseStream.Seek(offset, origin);
    }

    public override void SetLength(long length)
    {
    _responseStream.SetLength(length);
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
    return _responseStream.Read(buffer, offset, count);
    }
    }




  • 相关阅读:
    Django_redis_session
    python_redis操作
    Django_url反向解析
    Django_分页
    Django_cookie与sesstion
    Django 自定义错误页面 403 404...
    Django_设置静态文件、上传文件
    Django设置子路由
    nginx、uwsgi
    CentOS安装MySQL
  • 原文地址:https://www.cnblogs.com/pipizhu/p/2210514.html
Copyright © 2011-2022 走看看