• 开发过程中疑难杂症解决方案总结一


    一、批次加载列表数据
    问题场景:机票列表页面一直处于loading状态,服务器日志显示已经返回了数据,但是ajax请求一直处于挂起状态,导致页面也一直loading中。
    分析原因:通过排查,发现服务器返回的数据量过大(大约2M)导致ajax假死,网上有人说ajax请求的响应时间为10秒,超过了就会假死。
    解决方案:
    1、把原先的ajax请求分成多批次,每次请求让服务器返回5条数据,这样就避免了一次性响应数据量过大的问题;
    2、服务端把数据做缓存,分批次从缓存读取数据给客户端;
    3、客户端ajax每次请求返回后根据服务端返回的完成标识判断是否再次发送请求;
    相关代码:
    客户端:

    function getCalendarPriceListAndFlightList() {
        var info = {
            "depCity": $("#hiddepCity").val(),
            "arrCity": $("#hidarrCity").val(),
            "depDate": $("#hiddepDate").val(),
            "queryModule": "1", //查询类型  1-单程;2-往返去程;3-往返回程
            "lineType": "OW", //查询类型  OW-单程; RT-往返
            "uniqueKey": "", //携程舱位标识,返程查询需要
            "queryuuid": "", //查询的唯一标识
            "retType": "1", //数据返回模式 0:多批次返回,覆盖刷新界面展示  1:一次性全部返回(默认)
            "enterpriseId": $("#hidEnterpriseid").val(),
            "isLoaded": -1,
            "guidStr": "",
            "userName": $("#hidUserName").val(),
            "action": "getCalendarPriceListAndFlightList"
        };
        $.ajax({
            url: "../FlightHandler/JDFlightHandler.ashx",
            type: "post",
            data: info,
            dataType: "text",
            beforeSend: function (XMLHttpRequest) {
                $('.page-list-con').html('');
                createLoading();
            },
            success: function (data) {
                var dataArr = data.split('|');
                if (dataArr[2] != "") {
                    if (dataArr[0] == "-1")
                        $("#topPrice").text("¥");
                    else
                        $("#topPrice").text("¥" + dataArr[0]);
                    if (dataArr[1] == "-1")
                        $("#EndPrice").text("¥");
                    else
                        $("#EndPrice").text("¥" + dataArr[1]);
                    $('.page-list-con').html(dataArr[2]);
                    if (dataArr[5] == "-1")
                        $("#dqPrice").text("¥");
                    else
                        $("#dqPrice").text("¥" + dataArr[5]);
                    if (dataArr[6] == "-1")
                        $('#time_sel_airway').html();
                    else
                        $('#time_sel_airway').html(dataArr[6]);
    
                    //保存点击的出发城市、到达城市、开始时间、结束时间
                    $("#hidTempdepCity").val($("#hiddepCity").val());
                    $("#hidTemparrCity").val($("#hidarrCity").val());
                    $("#hidTempdepDate").val($("#hiddepDate").val());
                    $("#hidTemparrDate").val($("#hidarrDate").val());
                    if (dataArr[3] == "0") {
                        reloadFlightList(dataArr[3], dataArr[4]);
                    }
                } else {
                    $('.page-list-con').html(SetErroHtml());
                    alert("读取数据超时,请尝试重新查询!");
                }
            },
            complete: function (XMLHttpRequest, textStatus) {
                //removeLoading();
            },
            error: function () {
            }
        });
    }
    
    function reloadFlightList(isLoaded, guidStr) {
        var info = {
            "depCity": $("#hiddepCity").val(),
            "arrCity": $("#hidarrCity").val(),
            "depDate": $("#hiddepDate").val(),
            "arrDate": $("#hidarrDate").val(),
            "enterpriseId": $("#hidEnterpriseid").val(),
            "isLoaded": isLoaded,
            "guidStr": guidStr,
            "userName": $("#hidUserName").val(),
            "action": "getCalendarPriceListAndFlightList"
        };
        $.ajax({
            url: "../FlightHandler/JDFlightHandler.ashx",
            type: "post",
            data: info,
            dataType: "text",
            success: function (data) {
                var dataArr = data.split('|');
                if (dataArr[3] == "0") {
                    if (dataArr[2] != "") {
                        $("#tbFlightContainer").append(dataArr[2]);
                    }
                    reloadFlightList(isLoaded, guidStr);
                }
                else {
                    removeLoading();
                }
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                removeLoading();
                return;
            }
        });
    }
    

     
    服务端:

    public string getFlightList(HttpRequest Request, ref string interval, ref int isFinished, out decimal minPrice, string AccountName)
    {
        LogHelper.WriteLog("进入getFlightList方法");
        string retStr = string.Empty;
        string guidStr = "";
        int iswc = 1;
        minPrice = 0;
        try
        {
            string depCity = string.Empty;
            string arrCity = string.Empty;
            string depDate = string.Empty;
            string queryModule = string.Empty;
            string lineType = string.Empty;
            string uniqueKey = string.Empty;
            string queryuuid = string.Empty;
            string retType = string.Empty;
            if (!string.IsNullOrEmpty(Request.Form["depCity"]))
            {
                depCity = Request.Form["depCity"].ToString();
            }
            if (!string.IsNullOrEmpty(Request.Form["arrCity"]))
            {
                arrCity = Request.Form["arrCity"].ToString();
            }
            if (!string.IsNullOrEmpty(Request.Form["depDate"]))
            {
                depDate = Request.Form["depDate"].ToString();
            }
            if (!string.IsNullOrEmpty(Request.Form["queryModule"]))
            {
                queryModule = Request.Form["queryModule"].ToString();
            }
            if (!string.IsNullOrEmpty(Request.Form["lineType"]))
            {
                lineType = Request.Form["lineType"].ToString();
            }
            if (!string.IsNullOrEmpty(Request.Form["uniqueKey"]))
            {
                uniqueKey = Request.Form["uniqueKey"].ToString();
            }
            if (!string.IsNullOrEmpty(Request.Form["queryuuid"]))
            {
                queryuuid = Request.Form["queryuuid"].ToString();
            }
            if (!string.IsNullOrEmpty(Request.Form["retType"]))
            {
                retType = Request.Form["retType"].ToString();
            }
            string enterpriseId = Request.Form["enterpriseId"].ToString();
            string isLoaded = Request.Form["isLoaded"].ToString();
            string RguidStr = Request.Form["guidStr"].ToString();
            string userName = Request.Form["userName"].ToString();
    
            List<Common.JsonFlightInfo.FlightInfo> lstFlightInfo = null;
            List<Common.JsonFlightInfo.FlightInfo> lstFlightInfoEx = null;
            List<Common.JsonFlightInfo.FlightInfo> lstFlightInfoExFilter = null;
            List<JsonFlightInfo.FlightInfo> lst = null;
            //首次加载航班信息
            if (string.IsNullOrEmpty(RguidStr))
            {
                lst = PublicListDataBind(depCity, arrCity, depDate, queryModule, lineType, uniqueKey, queryuuid, retType, ref interval, ref isFinished);//获取机票数据
                if (lst!=null && lst.Count > 0)
                {
                    lstFlightInfo = lst;
                    lstFlightInfoEx = lst;
                    lstFlightInfoExFilter = lst;
                    //生成GUID缓存键
                    guidStr = System.Guid.NewGuid().ToString();
                    CacheHelper.SetCache("cache" + userName, lstFlightInfoExFilter, new TimeSpan(0, 10, 0));
                }
                else
                {
                    return "|1|";
                }
            }
            else
            {
                //非首次加载航班信息,读缓存
                lstFlightInfo = CacheHelper.GetCache(RguidStr) as List<Common.JsonFlightInfo.FlightInfo>;
                lstFlightInfoEx = CacheHelper.GetCache(RguidStr) as List<Common.JsonFlightInfo.FlightInfo>;
                //用回传过来的GUID键,继续读取缓存
                guidStr = RguidStr;
            }
            //集合里航班信息大于5条,每次就读取前5条,然后把其余数据放到缓存下次读取用。
            if (lstFlightInfoEx.Count > 5)
            {
                lstFlightInfo = lstFlightInfoEx.Skip(0).Take(5).ToList();
                CacheHelper.SetCache(guidStr, lstFlightInfoEx.Skip(5).ToList()); //航班信息保存到缓存
    
                if (lstFlightInfoEx.Skip(5).Count() < 1)
                    iswc = 1; //已完成
                else
                    iswc = 0; //未完成
            }
            else
            {
                //集合里航班信息小于5条时,就直接全部输出给页面,清除缓存
                if (!string.IsNullOrEmpty(RguidStr))
                {
                    CacheHelper.RemoveAllCache(RguidStr);
                }
                iswc = 1; //已完成
            }
            if (isLoaded == "-1")
            {
                List<string> listString = new List<string>();
                if (lst != null)
                {
                    foreach (Common.JsonFlightInfo.FlightInfo flightInfo in lst)
                    {
                        flightInfo.minPrice = Convert.ToDecimal(Common.Application.GetLeastPrice(flightInfo.flightNo, Request.Form["classFC"] == null ? "" : Request.Form["classFC"].ToString(),userName));
                        if (!listString.Contains(flightInfo.airwaysCn))
                        {
                            listString.Add(flightInfo.airwaysCn);
                            sbairway.Append("<li  name="airway" hkdm="" + flightInfo.airways + "">" + flightInfo.airwaysCn + "</li>");
                        }
                    }
                }
            }
            retStr = Common.HtmlFlightList.getHtmlFlightListWAP(lstFlightInfo, depCity, arrCity, "1", out minPrice, enterpriseId, userName);
            LogHelper.WriteLog("返回航班信息。");
        }
        catch (Exception ex)
        {
            LogHelper.WriteLog("getFlightList异常!异常信息:" + ex.Message + ",堆栈:" + ex.StackTrace);
            throw;
        }
    
        if (!string.IsNullOrEmpty(guidStr))
            return retStr + "|" + iswc + "|" + guidStr;
        else
            return retStr + "|" + iswc + "|";
    }
    

     
    问题总结:
    1、ajax请求响应时间为10秒,超过后请求就挂起,浏览器进入假死状态;
    2、jQuery ajax实现分批次请求数据;
    3、从Cache中利用linq分批次读取数据;

    注:
    用ajax设置请求头部超时时间,如:
    ajax.setRequestHeader("connectionTimeout","5000");


    二、APP自动登录实现和登录跳转问题
    需求场景:公司要做一个APP,套个壳,把现有的几个H5站点加进去。这样APP和H5端用户的登录信息需共享,并且当H5站点重启时不再跳转原H5的登录页面,而是跳转到APP的登录界面。
    解决方案:
    1、APP端通过把用户登录信息写入H5的cookie中来传递,当用户退出APP再次登录时cookie会更新。
    2、H5端站点通过HttpModule拦截HTTP请求,如果H5站点登录失效(比如MemCache或Session过期)就调用自动登录API来更新H5端的登录状态;
    3、如果H5站点重启(比如重新发布站点或修改web.config),则跳转到APP登录界面;
    相关代码:

    HttpModule实现:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Web;
    using System.Web.Script.Serialization;
    using System.Web.SessionState;
    using XFK.AppLYTravel.Common.CommonModel;
    using XFK.AppLYTravel.Common.Configuration;
    using XFK.AppLYTravel.Common.helper;
    using XFK.AppLYTravel.Common.Logs;
    using XFK.AppLYTravel.Common.Util;
    using XinfuMall.XinfuWeb.PublicClass;
    
    namespace XFK.AppLYTravel.Common
    {
        /// <summary>
        /// AutoLoginModule 的摘要说明
        /// </summary>
        public class AutoLoginModule : IHttpModule, IRequiresSessionState
        {
            public static readonly object syncObject = new object();
            public void Init(HttpApplication context)
            {
                LogHelper.WriteLog("进入HttpModule_Init方法。");
                context.EndRequest+=context_EndRequest;
            }
    
            void context_EndRequest(object sender, EventArgs e)
            {
                lock (syncObject)
                {
                    HttpApplication app = (HttpApplication)sender;
                    HttpContext _context = app.Context;
                    string originReq = app.Request.Headers["User-Agent"];
                    LogHelper.WriteLog("HttpModule获取请求头user_agent:" + originReq);
                    try
                    {
                        if (!string.IsNullOrEmpty(originReq))
                        {
                            //如果是来自APP的请求
                            if (originReq.ToLower().IndexOf("xinfukaapp") > -1)
                            {
    
                                string userNo = string.Empty;
                                string xf_sid = string.Empty;
                                if (_context.Request.Cookies["userNo"] != null)
                                {
                                    userNo = _context.Request.Cookies["userNo"].Value;
                                }
                                if (_context.Request.Cookies["xf_sid"] != null)
                                {
                                    xf_sid = _context.Request.Cookies["xf_sid"].Value;
                                }
    
                                LogHelper.WriteLog(string.Format("HttpModule获取到的cookie数据:userNo={0},xf_sid={1}", userNo, xf_sid));
                                bool isGoLogin = false;
                                if (!string.IsNullOrEmpty(userNo) && !string.IsNullOrEmpty(xf_sid))
                                {
    
                                    HttpContext.Current.Items["xf_sid"] = xf_sid;
                                    if (SessionManager.Read(UserUtil.user_sessionStr) != null)
                                    {
                                        LogHelper.WriteLog(string.Format("用户{0}处于已登录状态。", userNo));
                                    }
                                    else
                                    {
                                        LogHelper.WriteLog(string.Format("用户{0}登录已过期,需要自动登录。", userNo));
                                        string pstr = string.Format("userNo={0}&sessionID={1}", userNo, xf_sid);
                                        var url = ConfigurationManager.AppSettings["LoginAppAutoApi"];
                                        LogHelper.WriteLog(string.Format("调用APP自动登录接口:{0},入参:{1}", url, pstr));
                                        string strResult = JDAPI.PostWebRequest(url.ToString(), pstr);
                                        LogHelper.WriteLog("返回数据:" + strResult);
                                        JavaScriptSerializer js = new JavaScriptSerializer();
                                        GeneralResult loginResult = js.Deserialize<GeneralResult>(strResult);
                                        if (loginResult.Ret == "200" && loginResult.data != null)
                                        {
                                            LogHelper.WriteLog("用户" + userNo + "自动登录成功!");
                                        }
                                        else
                                        {
                                            isGoLogin = true;
                                        }
                                    }
                                }
                                else
                                {
                                    isGoLogin = true;
                                }
                                if (isGoLogin)
                                {
                                    LogHelper.WriteLog("用户" + userNo + "自动登录失败!需重新手工登录。");
                                    string mimeStr = _context.Response.ContentType;
                                    LogHelper.WriteLog("获取到的请求中mime类型:" + mimeStr);
                                    if (!string.IsNullOrEmpty(mimeStr))
                                    {
                                        //当请求的是页面
                                        if (mimeStr.IndexOf(@"text/html") > -1)
                                        {
    
                                                if (originReq.Equals("XinfukaAppAndroid"))
                                                {
                                                    LogHelper.WriteLog("检测到客户端是安卓系统,跳转APP登录。");
                                                    _context.Response.Write("<script type="text/javascript">window.AndroidInterface.tokenTimeOut();</script>");
                                                    _context.Response.End();
                                                }
                                                else if (originReq.Equals("XinfukaAppIos"))
                                                {
                                                    LogHelper.WriteLog("检测到客户端是IOS系统,跳转APP登录。");
                                                    StringBuilder sb = new StringBuilder();
                                                    sb.Append("<script type="text/javascript"> function loadURL(url) {");
                                                    sb.Append("var iFrame;");
                                                    sb.Append("iFrame = document.createElement("iframe");");
                                                    sb.Append("iFrame.setAttribute("src", url);");
                                                    sb.Append("iFrame.setAttribute("style", "display:none;");");
                                                    sb.Append("iFrame.setAttribute("height", "0px");");
                                                    sb.Append("iFrame.setAttribute("width", "0px");");
                                                    sb.Append("iFrame.setAttribute("frameborder", "0");");
                                                    sb.Append("document.body.appendChild(iFrame);");
                                                    sb.Append("iFrame.parentNode.removeChild(iFrame);");
                                                    sb.Append("iFrame = null;");
                                                    sb.Append("}");
                                                    sb.Append("loadURL("haleyAction://tokenTimeOut");</script>");
                                                    _context.Response.Write(sb.ToString());
                                                    _context.Response.End();
                                                }
                                                else
                                                {
                                                    LogHelper.WriteLog("无效识别。");
                                                    _context.Response.Write("无效识别。");
                                                    _context.Response.End();
                                                }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (System.Threading.ThreadAbortException) { }
                    catch (Exception ex)
                    {
                        LogHelper.WriteLog("用户自动登录异常,信息:" + ex.Message + ",堆栈:" + ex.StackTrace);
                    }
                }
            }
    
            public void Dispose()
            {
            }
        }
    }
    

     H5站点引入:
    <system.webServer>
        <modules>
          <add name="AutoLoginModuleNew" type="XFK.AppLYTravel.Common.AutoLoginModule,XFK.AppLYTravel.Common" />
        </modules>
    </system.webServer>

    H5跳转方法

    public static void AppRedirect(HttpContext context, Action cusAction)
    {
        LogHelper.WriteLog("进入AppRedirect方法。");
        HttpContext _context = context;
        string originReq = _context.Request.Headers["User-Agent"];
        LogHelper.WriteLog("AppRedirect获取请求头user_agent:" + originReq);
        try
        {
            if (!string.IsNullOrEmpty(originReq))
            {
                //如果是来自APP的请求
                if (originReq.ToLower().IndexOf("xinfukaapp") > -1)
                {
                    string mimeStr = _context.Response.ContentType;
                    LogHelper.WriteLog("AppRedirect获取到的请求中mime类型:" + mimeStr);
                    if (!string.IsNullOrEmpty(mimeStr))
                    {
                        //当请求的是页面
                        if (mimeStr.IndexOf(@"text/html") > -1)
                        {
                            LoginInfo sessionInfo = _context.Session["UserLoginInfo"] as LoginInfo;
                            if (sessionInfo == null)
                            {
                                LogHelper.WriteLog("session信息为空!");
                                if (originReq.Equals("XinfukaAppAndroid"))
                                {
                                    LogHelper.WriteLog("AppRedirect检测到客户端是安卓系统,跳转APP登录。");
                                    _context.Response.Write("<script type="text/javascript">window.AndroidInterface.tokenTimeOut();</script>");
                                    _context.Response.End();
                                }
                                else if (originReq.Equals("XinfukaAppIos"))
                                {
                                    LogHelper.WriteLog("AppRedirect检测到客户端是IOS系统,跳转APP登录。");
                                    StringBuilder sb = new StringBuilder();
                                    sb.Append("<script type="text/javascript"> function loadURL(url) {");
                                    sb.Append("var iFrame;");
                                    sb.Append("iFrame = document.createElement("iframe");");
                                    sb.Append("iFrame.setAttribute("src", url);");
                                    sb.Append("iFrame.setAttribute("style", "display:none;");");
                                    sb.Append("iFrame.setAttribute("height", "0px");");
                                    sb.Append("iFrame.setAttribute("width", "0px");");
                                    sb.Append("iFrame.setAttribute("frameborder", "0");");
                                    sb.Append("document.body.appendChild(iFrame);");
                                    sb.Append("iFrame.parentNode.removeChild(iFrame);");
                                    sb.Append("iFrame = null;");
                                    sb.Append("}");
                                    sb.Append("loadURL("haleyAction://tokenTimeOut");</script>");
                                    _context.Response.Write(sb.ToString());
                                    _context.Response.End();
                                }
                                else
                                {
                                    LogHelper.WriteLog("AppRedirect无效识别。");
                                    _context.Response.Write("AppRedirect无效识别。");
                                    _context.Response.End();
                                }
                            }
                        }
                    }
                }
                else
                {
                    cusAction.Invoke();
                }
            }
        }
        catch (System.Threading.ThreadAbortException) { }
        catch (Exception ex)
        {
            LogHelper.WriteLog("AppRedirect异常,信息:" + ex.Message + ",堆栈:" + ex.StackTrace);
        }
    }
    

    H5端在BasePage中调用,如:

    using Common;
    using Model;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.Script.Serialization;
    using System.Web.SessionState;
    using XinfuMall.XinfuWeb.PublicClass;
    
    /// <summary>
    /// PageBase 的摘要说明
    /// </summary>
    public class PageBase : System.Web.UI.Page
    {
        public PageBase()
        {
        }
    
        private string accountName;
        private string enterpriseid;
        public string AccountName
        {
            get { return this.accountName; }
        }
        public string Enterpriseid
        {
            get { return this.enterpriseid; }
        }
        protected override void OnInit(EventArgs e)
        {
            if (HttpContext.Current.Request.Cookies["xf_sid"] == null && XFK.Infrastructure.Util.SessionManager.Read(UserUtil.user_sessionStr) == null)
            {
                Response.Redirect(System.Configuration.ConfigurationManager.AppSettings["xinfuUrl"] + "mall/Login?originUrl=" + HttpUtility.UrlEncode(Request.Url.AbsoluteUri, System.Text.Encoding.UTF8));
            }
            else
            {
                LoginInfo loginfo = Session["UserLoginInfo"] as LoginInfo;
                if (loginfo == null)
                {
                   XFK.AppLYTravel.Common.CommUtil.AppRedirect(HttpContext.Current,WebRedirect);
                }
                this.accountName = loginfo.AccountName;
                this.enterpriseid = loginfo.Enterpriseid;
    
                var limitEnterprise = String.IsNullOrEmpty(System.Configuration.ConfigurationManager.AppSettings["limitEnterprise"]) ? "" : System.Configuration.ConfigurationManager.AppSettings["limitEnterprise"];
                if (limitEnterprise.Split(',').Contains(loginfo.Enterpriseid.ToString()))
                {
                    System.Web.HttpContext.Current.Response.Write("对不起,所属的企业没有订购此产品的权限!");
                    System.Web.HttpContext.Current.Response.End();
                }
            }
        }
    
        void WebRedirect()
        {
            Response.Redirect(System.Configuration.ConfigurationManager.AppSettings["xinfuUrl"] + "mall/Login?originUrl=" + HttpUtility.UrlEncode(Request.Url.AbsoluteUri, System.Text.Encoding.UTF8));
        }
    }
    

     
    遇到的问题:
    1、H5如何判断请求来自APP;
    2、HttpModule获取请求资源mime类型的时机;
    3、Http请求管道事件(如BeginRequest、EndRequest)对于js脚本执行的影响;
    例如IOS端跳转APP登录页的方法是这样的:

    <script>
        function loadURL(url) {
            var iFrame;
            iFrame = document.createElement("iframe");
            iFrame.setAttribute("src", url);
            iFrame.setAttribute("style", "display:none;");
            iFrame.setAttribute("height", "0px");
            iFrame.setAttribute("width", "0px");
            iFrame.setAttribute("frameborder", "0");
            document.body.appendChild(iFrame);
            iFrame.parentNode.removeChild(iFrame);
            iFrame = null;
        }
        loadURL("haleyAction://tokenTimeOut");
    </script>
    

    这段js代码在EndRequest事件中可以输出到</html>标签外,页面最底部,如下图:

    这时候所有的DOM元素都已加载完毕,所以执行没问题;
    但是放在BeginRequest里,js代码被输出到了页面最顶部,如:

    这时候因为DOM元素还未加载好,会有如下错误:


    解决方案:
    1、APP端通过修改http请求头User-Agent来标识;
    2、精确获取mime类型要在EndRequest事件里,如:string mimeStr = _context.Response.ContentType;
    在BeginRequest里不管请求资源是页面、脚本、图片或是其他,获取的都是"text/html"

    3、这种情况,用window.onload包装一下就可以正常执行了,如:

    <script>
        window.onload=function(){
            function loadURL(url) {
                var iFrame;
                iFrame = document.createElement("iframe");
                iFrame.setAttribute("src", url);
                iFrame.setAttribute("style", "display:none;");
                iFrame.setAttribute("height", "0px");
                iFrame.setAttribute("width", "0px");
                iFrame.setAttribute("frameborder", "0");
                document.body.appendChild(iFrame);
                iFrame.parentNode.removeChild(iFrame);
                iFrame = null;
            }
            loadURL("haleyAction://tokenTimeOut");
        }
    </script>
    

     
    总结:
    1、HttpModule的BeginRequest、EndRequest事件对于页面元素(HTML和js)加载顺序的影响;
    2、获取mime类型一定要在EndRequest事件里,并且用Response.ContentType方法;
    3、session依赖于cookie,当cookie在页面中失效后session也会失效;

    三、用到的或了解到的跨域知识总结
    1、WEB站点调用远程API,通过Ajax请求本地Handler或Controller,而本地Handler或Controller利用HttpWebRequest和HttpWebResponse与远程API交互;
    2、WEB站点在调用远程登录接口时,HTTP请求中带上cookie,实现统一登录;
    3、实现跨域的技术如JSONP、CORS、postMessage等作为技术储备;

  • 相关阅读:
    策略梯度训练cartpole小游戏
    关于不执行整个大项目而是执行其中一部分独立文件夹的时候的python运行方法
    和textrank4ZH代码一模一样的算法详细解读
    K8s常用命令
    python标准库
    chrome通过devtools来查看Devtools Extension与浏览器内核实际通信的数据情况
    修改文件MD5值
    使用charles过滤网络请求
    git中working tree, index, commit
    Maven中settings.xml的配置项说明
  • 原文地址:https://www.cnblogs.com/zhaow/p/8968004.html
Copyright © 2020-2023  润新知