webapi 异常信息返回前台了_webapi如何将两个集合返回到前台 - CSDN
精华内容
参与话题
  • webApi里设置全局异常返回格式 今天为了设置api返回格式统一,在网上找了一推资料,各种资料参差不齐的,最后自己捣鼓,终于弄出来了,直接上代码 /// /// 消息代理处理,用来捕获这些特殊的异常信息 /// ...

    webApi里设置全局异常返回格式

    今天为了设置api返回格式统一,在网上找了一推资料,各种资料参差不齐的,最后自己捣鼓,终于弄出来了,直接上代码

        /// <summary>
        /// 消息代理处理,用来捕获这些特殊的异常信息
        /// </summary>
        public class CustomErrorMessageDelegatingHandler : DelegatingHandler
        {
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
                {
                    HttpResponseMessage response = responseToCompleteTask.Result;
                    HttpError error = null;
                    if (response.TryGetContentValue<HttpError>(out error))
                    {
                        //自定义错误处理
                        //error.Message = "这个接口调用出错了";
                    }
                    if (error != null)
                    {   //这是本人创建的一个返回类                 
                        var resultMsg = new ResultMsg { StatusCode = (int)StatusCodeEnum.HttpUrlEror, Info =error.MessageDetail  };
                        return new HttpResponseMessage { Content = new StringContent(resultMsg.ToJson(), 
                            System.Text.Encoding.GetEncoding("UTF-8"), "application/json"), StatusCode = HttpStatusCode.OK };
                    }
                    else
                    {
                        return response;
                    }
                });
            }
        }
    然后就是注册该cs文件,找到Global.asax文件
     	protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
                //FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                //RouteConfig.RegisterRoutes(RouteTable.Routes);
                //BundleConfig.RegisterBundles(BundleTable.Bundles);
                GlobalConfiguration.Configure(WebApiConfig.Register);
                GlobalConfiguration.Configuration.Filters.Add(new ErrorHandler());
            }

    最后大功告成,效果:
    {
      "StatusCode": 404,
      "Info": "在控制器“StudyTask”上找不到与该请求匹配的操作。",
      "Data": null
    }



    最后,本人技术菜鸟,有好的建议希望分享,谢谢


    展开全文
  • 工具: 1.Visual Studio 2017 V15.3.5+ ...关于.net core或者.net core 2.0的相关知识就不介绍了, 这里主要是从头编写一个asp.net core 2.0 web api的基础框架.   我最近几年一直在使用asp.net web api (传

    工具:

    1.Visual Studio 2017 V15.3.5+

    2.Postman (Chrome的App)

    3.Chrome (最好是)

    关于.net core或者.net core 2.0的相关知识就不介绍了, 这里主要是从头编写一个asp.net core 2.0 web api的基础框架.

     

    我最近几年一直在使用asp.net web api (传统.net framework)作为后台Api, 前台使用 angularjs 1.2 或者 1.6进行开发, 自己独立做过10多个基于这两个技术的项目吧. 在此之前, 我是搞java的, 因为我不受限于公司, 所以我决定放弃java, .net非常适合我.

    我一直在关注asp.net core 和 angular 2/4, 并在用这对开发了一些比较小的项目. 现在我感觉是时候使用这两个技术去为企业开发大一点的项目了, 由于企业有时候需要SSO(单点登录), 所以我一直在等待Identity Server4以及相关库的正式版, 现在匹配2.0的RC版已经有了, 所以这个可以开始编写了.

    这个系列就是我从头开始建立我自己的基于asp.net core 2.0 web api的后台api基础框架过程, 估计得分几次才能写完. 如果有什么地方错的, 请各位指出!!,谢谢.

     

    创建项目:

    1.选择asp.net core web application.

    640?wx_fmt=png&wxfrom=5&wx_lazy=1

    2.选择.net core, asp.net core 2.0, 然后选择Empty (因为是从头开始):

    0?wx_fmt=png

    下面看看项目生成的代码:

    Program.cs


    namespace CoreBackend.Api
    {    public class Program
        {        public static void Main(string[] args)
            {
                BuildWebHost(args).Run();
            }        public static IWebHost BuildWebHost(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>()
                    .Build();
        }
    }

    这个Program是程序的入口, 看起来很眼熟, 是因为asp.net core application实际就是控制台程序(console application).

    它是一个调用asp.net core 相关库的console application. 

    Main方法里面的内容主要是用来配置和运行程序的.

    因为我们的web程序需要一个宿主, 所以 BuildWebHost这个方法就创建了一个WebHostBuilder. 而且我们还需要Web Server.

    看一下WebHost.CreateDefaultBuilder(args)的源码:

    public static IWebHostBuilder CreateDefaultBuilder(string[] args)
            {            var builder = new WebHostBuilder()
                    .UseKestrel()
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .ConfigureAppConfiguration((hostingContext, config) =>
                    {                    var env = hostingContext.HostingEnvironment;
    
                        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                              .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);                    if (env.IsDevelopment())
                        {                        var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));                        if (appAssembly != null)
                            {
                                config.AddUserSecrets(appAssembly, optional: true);
                            }
                        }
    
                        config.AddEnvironmentVariables();                    if (args != null)
                        {
                            config.AddCommandLine(args);
                        }
                    })
                    .ConfigureLogging((hostingContext, logging) =>
                    {
                        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                        logging.AddConsole();
                        logging.AddDebug();
                    })
                    .UseIISIntegration()
                    .UseDefaultServiceProvider((context, options) =>
                    {
                        options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
                    });      
          
    return builder;        }

    asp.net core 自带了两种http servers, 一个是WebListener, 它只能用于windows系统, 另一个是kestrel, 它是跨平台的.

    kestrel是默认的web server, 就是通过UseKestrel()这个方法来启用的.

    但是我们开发的时候使用的是IIS Express, 调用UseIISIntegration()这个方法是启用IIS Express, 它作为Kestrel的Reverse Proxy server来用.

    如果在windows服务器上部署的话, 就应该使用IIS作为Kestrel的反向代理服务器来管理和代理请求.

    如果在linux上的话, 可以使用apache, nginx等等的作为kestrel的proxy server.

    当然也可以单独使用kestrel作为web 服务器, 但是使用iis作为reverse proxy还是由很多有点的: 例如,IIS可以过滤请求, 管理证书, 程序崩溃时自动重启等.

    UseStartup<Startup>(), 这句话表示在程序启动的时候, 我们会调用Startup这个类.

    Build()完之后返回一个实现了IWebHost接口的实例(WebHostBuilder), 然后调用Run()就会运行Web程序, 并且阻止这个调用的线程, 直到程序关闭.

    BuildWebHost这个lambda表达式最好不要整合到Main方法里面, 因为Entity Framework 2.0会使用它, 如果把这个lambda表达式去掉之后, Add-Migration这个命令可能就不好用了!!!

    Startup.cs


    namespace CoreBackend.Api
    {    public class Startup
        {        // This method gets called by the runtime. Use this method to add services to the container.        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
            public void ConfigureServices(IServiceCollection services)
            {
            }        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {            if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.Run(async (context) =>
                {                await context.Response.WriteAsync("Hello World!");
                });
            }
        }
    }


    其实Startup算是程序真正的切入点.

    ConfigureServices方法是用来把services(各种服务, 例如identity, ef, mvc等等包括第三方的, 或者自己写的)加入(register)到container(asp.net core的容器)中去, 并配置这些services. 这个container是用来进行dependency injection的(依赖注入). 所有注入的services(此外还包括一些框架已经注册好的services) 在以后写代码的时候, 都可以将它们注入(inject)进去. 例如上面的Configure方法的参数, app, env, loggerFactory都是注入进去的services.

    Configure方法是asp.net core程序用来具体指定如何处理每个http请求的, 例如我们可以让这个程序知道我使用mvc来处理http请求, 那就调用app.UseMvc()这个方法就行. 但是目前, 所有的http请求都会导致返回"Hello World!".

    这几个方法的调用顺序: Main -> ConfigureServices -> Configure

    请求管道和中间件(Request Pipeline, Middleware)

    请求管道: 那些处理http requests并返回responses的代码就组成了request pipeline(请求管道).

    中间件: 我们可以做的就是使用一些程序来配置那些请求管道 request pipeline以便处理requests和responses. 比如处理验证(authentication)的程序, 连MVC本身就是个中间件(middleware).

    0?wx_fmt=png

    每层中间件接到请求后都可以直接返回或者调用下一个中间件. 一个比较好的例子就是: 在第一层调用authentication验证中间件, 如果验证失败, 那么直接返回一个表示请求未授权的response.

    app.UseDeveloperExceptionPage(); 就是一个middleware, 当exception发生的时候, 这段程序就会处理它. 而判断env.isDevelopment() 表示, 这个middleware只会在Development环境下被调用.

    可以在项目的属性Debug页看到这个设置: 

    0?wx_fmt=png

    需要注意的是这个环境变量Development和VS里面的Debug Build没有任何关系.

    在正式环境中, 我们遇到exception的时候, 需要捕获并把它记录(log)下来, 这时候我们应该使用这个middleware: Exception Handler Middleware, 我们可以这样调用它:

                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }            else
                {                app.UseExceptionHandler();
                }

    UseExceptionHandler是可以传参数的, 但暂时先这样, 我们在app.Run方法里抛一个异常, 然后运行程序, 在Chrome里按F12就会发现有一个(或若干个, 多少次请求, 就有多少个错误)500错误.

    用来创建 Web Api的middleware:

     原来的.net使用asp.net web api 和 asp.net mvc 分别来创建 web api和mvc项目. 但是 asp.net core mvc把它们整合到了一起.

    MVC Pattern

    model-view-controller 它的定义是: MVC是一种用来实现UI的架构设计模式. 但是网上有很多解释, 有时候有点分不清到底是干什么的. 但是它肯定有这几个有点: 松耦合, Soc(Separation of concerns), 易于测试, 可复用性强等.

    但是MVC绝对不是完整的程序架构, 在一个典型的n层架构里面(presentation layer 展示层, business layer 业务层, data access layer数据访问层, 还有服务处), MVC通常是展示层的. 例如angular就是一个客户端的MVC模式.

    在Web api里面的View就是指数据或者资源的展示, 通常是json.

    注册并使用MVC

    因为asp.net core 2.0使用了一个大而全的metapackage, 所以这些基本的services和middleware是不需要另外安装的.

    首先, 在ConfigureServices里面向Container注册MVC: services.AddMvc();

            public void ConfigureServices(IServiceCollection services)
            {            services.AddMvc(); // 注册MVC到Container
            }

    然后再Configure里面告诉程序使用mvc中间件:


            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {            if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }            else
                {
                    app.UseExceptionHandler();
                }            app.UseMvc();


    注意顺序, 应该在处理异常的middleware后边调用app.UseMvc(), 所以处理异常的middleware可以在把request交给mvc之间就处理异常, 更总要的是它还可以捕获并处理返回MVC相关代码执行中的异常.

    然后别忘了把app.Run那部分代码去掉. 然后改回到Develpment环境, 跑一下, 试试效果:

    Chrome显示了一个空白页, 按F12, 显示了404 Not Found错误.

    这是因为我只添加了MVC middleware, 但是它啥也没做, 也没有找到任何可用于处理请求的代码, 所以我们要添加Controller来返回数据/资源等等.

    Asp.net Core 2 Metapackage 和 Runtime Store

    Asp.net core 2 metapackage, asp.net core 2.0开始, 所有必须的和常用的库也包括少许第三方库都被整和到了这个大而全的asp.net core 2 metapackage里面, 所以开发者就不必自己挨个库安装也没有版本匹配问题了.

    Runtime Store, 有点像以前的GAC, 在系统里有一个文件夹里面包含所有asp.net core 2程序需要运行的库(我电脑的是: C:\Program Files\dotnet\store\x64\netcoreapp2.0), 每个在这台电脑上运行的asp.net core 2应用只需调用这些库即可. 

    它的优点是:

    1. 部署快速, 不需要部署这里面包含的库;

    2. 节省硬盘空间, 多个应用程序都使用同一个store, 而不必每个程序的文件夹里面都部署这些库文件. 

    3. 程序启动更快一些. 因为这些库都是预编译好的.

    缺点是: 服务器上需要安装.net core 2.0

    但是, 也可以不引用Runtime Store的库, 自己在部署的时候挨个添加依赖的库.

    Controller

    首先建立一个Controllers目录, 然后建立一个ProductController.cs, 它需要继承Microsoft.AspNetCore.Mvc.Controller

    我们先建立一个方法返回一个Json的结果.

    先建立一个Dto(Data Transfer Object) Product:

    namespace CoreBackend.Api.Dtos
    {  
      
    public class Product    {      
     
    public int Id { get; set; }      
     
    public string Name { get; set; }  
         
    public decimal Price { get; set; }    } }

    然后在Controller里面写这个Get方法:

    namespace CoreBackend.Api.Controllers
    {   
     
    public class ProductController: Controller    {      
      
    public JsonResult GetProducts()        {            

    return new JsonResult(new List<Product>            {                new Product                {                    Id = 1,                    Name = "牛奶",                    Price = 2.5f                },                new Product                {                    Id = 2,                    Name = "面包",                    Price = 4.5f                }            });        }    } }

    0?wx_fmt=gif

    然后运行, 并使用postman来进行请求:

    0?wx_fmt=png

    请求的网址返回404 Not Found, 因为还没有配置路由 Routing, 所以MVC不知道如何处理/映射这些URI.

    Routing 路由

    路由有两种方式: Convention-based (按约定), attribute-based(基于路由属性配置的). 

    其中convention-based (基于约定的) 主要用于MVC (返回View或者Razor Page那种的).

    Web api 推荐使用attribute-based.

    这种基于属性配置的路由可以配置Controller或者Action级别, uri会根据Http method然后被匹配到一个controller里具体的action上.

    常用的Http Method有:

    • Get, 查询, Attribute: HttpGet, 例如: '/api/product', '/api/product/1'

    • POST, 创建, HttpPost, '/api/product'

    • PUT 整体修改更新 HttpPut, '/api/product/1'

    • PATCH 部分更新, HttpPatch, '/api/product/1'

    • DELETE 删除, HttpDelete, '/api/product/1

    还有一个Route属性(attribute)也可以用于Controller层, 它可以控制action级的URI前缀.

    namespace CoreBackend.Api.Controllers
    { 
       
    //[Route("api/product")] [Route("api/[controller]")]  
     
    public class ProductController: Controller    {      
     [HttpGet]      
     
    public JsonResult GetProducts()        {        
       
    return new JsonResult(new List<Product>            {            
                   
    new Product                {                    Id = 1,                    Name = "牛奶",                    Price = 2.5f                },                new Product                {                    Id = 2,                    Name = "面包",                    Price = 4.5f                }            });        }    } }

    使用[Route("api/[controller]")], 它使得整个Controller下面所有action的uri前缀变成了"/api/product", 其中[controller]表示XxxController.cs中的Xxx(其实是小写).

    也可以具体指定, [Route("api/product")], 这样做的好处是, 如果ProductController重构以后改名了, 只要不改Route里面的内容, 那么请求的地址不会发生变化.

    然后在GetProducts方法上面, 写上HttpGet, 也可以写HttpGet(). 它里面还可以加参数,例如: HttpGet("all"), 那么这个Action的请求的地址就变成了 "/api/product/All".

    运行结果:

    0?wx_fmt=png

    我们把获取数据的代码整理成一个ProductService, 然后保证程序运行的时候, 操作的是同一批数据:

    namespace CoreBackend.Api.Services
    {    

    public class ProductService    {        

    public static ProductService CurrentProducts { get; } = new ProductService();    
        
    public List<Product> Products { get; }        

    private ProductService()        {            Products = new List<Product>            {                new Product                {                    Id = 1,                    Name = "牛奶",                    Price = 2.5f                },                new Product                {                    Id = 2,                    Name = "面包",                    Price = 4.5f                },                new Product                {                    Id = 3,                    Name = "啤酒",                    Price = 7.5f                }            };        }    } }


    然后修改一下Controller里面的代码:


    namespace CoreBackend.Api.Controllers
    {
        [Route("api/[controller]")]  
     
    public class ProductController: Controller    {        [HttpGet]    
       
    public JsonResult GetProducts()        {          
     
    return new JsonResult(ProductService.Current.Products);        }    } }


    也是同样的运行效果.

    再写一个查询单笔数据的方法:

            [Route("{id}")]        public JsonResult GetProduct(int id)
            {            return new JsonResult(ProductService.Current.Products.SingleOrDefault(x => x.Id == id));
            }

    这里Route参数里面的{id}表示该action有一个参数名字是id. 这个action的地址是: "/api/product/{id}"

    测试一下:

    0?wx_fmt=png

    如果请求一个id不存在的数据:

    0?wx_fmt=png

    Status code还是200, 内容是null. 因为框架找到了匹配uri的action, 所以不会返回404, 但是我们如果找不到数据的话, 应该返回404错误才比较好.

    Status code

    http status code 是reponse的一部分, 它提供了这些信息: 请求是否成功, 失败的原因. 

    web api 能涉及到的status codes主要是这些:

    200: OK

    201: Created, 创建了新的资源

    204: 无内容 No Content, 例如删除成功

    400: Bad Request, 指的是客户端的请求错误.

    401: 未授权 Unauthorized.

    403: 禁止操作 Forbidden. 验证成功, 但是没法访问相应的资源

    404: Not Found 

    409: 有冲突 Conflict.

    500: Internal Server Error, 服务器发生了错误.

    返回Status Code

    目前我们返回的JsonResult继承与ActionResult, ActionResult实现了IActionResult接口.

    因为web api不一定返回的都是json类型的数据, 也不一定只返回一堆json(可能还要包含其他内容). 所以JsonResult并不合适作为Action的返回结果.

    例如: 我们想要返回数据和Status Code, 那么可以这样做:


            [HttpGet]     
           
    public JsonResult GetProducts()        {      
         
    var temp = new JsonResult(ProductService.Current.Products)            {              
      StatusCode
    = 200            };        
                  
    return temp;        }


    但是每个方法都这么写太麻烦了.

    asp.net core 内置了很多方法都可以返回IActionResult.

    Ok, NotFound, BadRequest等等.

    所以改一下方法:

    namespace CoreBackend.Api.Controllers
    {
        [Route("api/[controller]")]  
     
    public class ProductController : Controller    {        [HttpGet]    
           
    public IActionResult GetProducts()        {          
              
    return Ok(ProductService.Current.Products);        }        [Route("{id}")]    
       
    public IActionResult GetProduct(int id)        {        
       
    var product = ProductService.Current.Products.SingleOrDefault(x => x.Id == id);          
      
    if (product == null)            {            
            
    return NotFound();            }          
              
    return Ok(product);        }    } }

    现在, 请求id不存在的数据时, 就返回404了.

    0?wx_fmt=png

    如果我们用chrome直接进行这个请求, 它的效果是这样的:

    0?wx_fmt=png

    StatusCode Middleware

    asp.net core 有一个 status code middleware, 使用一下这个middleware看看效果:

            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {            if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }            else
                {
                    app.UseExceptionHandler();
                }
    
                app.UseStatusCodePages(); // !!!
                app.UseMvc();
            }

    0?wx_fmt=png

    现在更友好了一些.

    子资源 Child Resources

    有时候, 两个model之间有主从关系, 会根据主model来查询子model.

    先改一下model: 添加一个Material作为Product子model. 并在Product里面添加一个集合导航属性.


    namespace CoreBackend.Api.Dtos
    {   
     
    public class Product    {      
     
    public int Id { get; set; }      
     
    public string Name { get; set; }    
       
    public float Price { get; set; }    

       
    public ICollection<Material> Materials { get; set; }    }  

     
    public class Material    {      
      
    public int Id { get; set; }    
       
    public int Name { get; set; }    } }


    改下ProductService:

    0?wx_fmt=gif View Code

    创建子Controller

    MaterialController:

    namespace CoreBackend.Api.Controllers
    {   
    [Route(
    "api/product")] // 和主Model的Controller前缀一样 public class MaterialController : Controller    {      
    [HttpGet(
    "{productId}/materials")]    
       
    public IActionResult GetMaterials(int productId)        {          
      
    var product = ProductService.Current.Products.SingleOrDefault(x => x.Id == productId);        
       
    if (product == null)            {              
     
    return NotFound();            }            return Ok(product.Materials);        }    
       [HttpGet(
    "{productId}/materials/{id}")]  
         
    public IActionResult GetMaterial(int productId, int id)        {          
      
    var product = ProductService.Current.Products.SingleOrDefault(x => x.Id == productId);          
      
    if (product == null)            {            
       
    return NotFound();            }          
     
    var material = product.Materials.SingleOrDefault(x => x.Id == id);          
     
    if (material == null)            {                return NotFound();            }            return Ok(material);        }    } }

    测试一下, 很成功:

    0?wx_fmt=png

    0?wx_fmt=png

    结果的格式

    asp.net core 2.0 默认返回的结果格式是Json, 并使用json.net对结果默认做了camel case的转化(大概可理解为首字母小写). 

    这一点与老.net web api 不一样, 原来的 asp.net web api 默认不适用任何NamingStrategy, 需要手动加上camelcase的转化.

    我很喜欢这样, 因为大多数前台框架例如angular等都约定使用camel case.

    如果非得把这个规则去掉, 那么就在configureServices里面改一下:

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc()                .AddJsonOptions(options =>
                    {
                        if (options.SerializerSettings.ContractResolver is DefaultContractResolver resolver)
                        {
                            resolver.NamingStrategy = null;
                        }
                    });
            }

    现在就是这样的结果了:

    0?wx_fmt=png

    但是还是默认的比较好.

    内容协商 Content Negotiation

    如果 web api提供了多种内容格式, 那么可以通过Accept Header来选择最好的内容返回格式: 例如:

    application/json, application/xml等等

    如果设定的格式在web api里面没有, 那么web api就会使用默认的格式.

    asp.net core 默认提供的是json格式, 也可以配置xml等格式.

    目前只考虑 Output formatter, 就是返回的内容格式.

    试试: json:

    0?wx_fmt=png

    xml:

    0?wx_fmt=png

    设置header为xml后,返回的还是json, 这是因为asp.net core 默认只实现了json.

    可以在ConfigureServices里面修改Mvc的配置来添加xml格式:

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc()                .AddMvcOptions(options =>
                    {
                        options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
                    });
            }

    然后试试:

    首先不写Accept Header:

    0?wx_fmt=png

    然后试试accept xml :

    0?wx_fmt=png

     

    原文地址:http://www.cnblogs.com/cgzl/p/7637250.html


    .NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

    640?wx_fmt=jpeg

    展开全文
  • 可同时参见这篇文章 asp.net webapi下json传值方式 纠缠了我几天的一个问题,简单摘抄整理下,希望对大家有帮助。 网络上大量使用json格式传递数据,json传递数据比较轻量,而用json传递数据就要解决两个问题: 1...

    可同时参见这篇文章  asp.net webapi下json传值方式

    纠缠了我几天的一个问题,简单摘抄整理下,希望对大家有帮助。

    网络上大量使用json格式传递数据,json传递数据比较轻量,而用json传递数据就要解决两个问题:
    1、从服务器回发回来的json格式的字符串该如何处理;
    2、如何将json数据提交到服务器并在服务器端解析json数据

    范例一:

    (asp.net mvc3.0代码,传递简单几个参数数值,后台使用的mvc的model binding方式获取值)

     

     

     

    范例二:

    (asp.net mvc 4.0下web api,使用了knockout.js 2.0的代码,传递参数为一个类,viewmodel。 使用的webapi 下的formatters传值方式,后台是从request的body中取值,并且是把整个body作为一个(不可为多个)对象解析为一个参数,故后台需定义一个对于的类结构来匹配前台的传来的复杂数据 类型 )

     

     

    范例三:

    (asp.net mvc 4.0下web api,使用了knockout.js 2.0的代码,传递参数为一个包含数组的自定义类型,使用的webapi 下的formatters传值方式 )

    范例四:

    (asp.net mvc 4.0下普通controller判断ajax请求,传递参数为一个拼接的json字符串,使用的webapi 下的formatters传值方式 )

     

    1)借助JSON.stringify函数将js对象转成json字符串格式

    var bookInfo = new Array();

    for (var i in self.dates()) {
    var bi = {};
    bi["datesNum"] = self.dates()[i].date;
    bi["totalPrice"] = self.dates()[i].date;
    bi["stylistId"] = self.dates()[i].date;
    bookInfo.push(bi);
    }
    var book = {
    book: bookInfo,
    name:"11",
    };

    var bookString=JSON.stringify(book);

    2)拼接json字符串

    //此类用来反序列化客户端json字符串

     

     

    json简单介绍

    1、JSON简介及其应用场景

           JSON协议是一种数据传输协议,你也可以把它理解为表达数据协议,JSON与XML不同,JSON只能用来传输数据,而不能用作文档格式。

        JSON 即 JavaScript Object Natation,它是一种轻量级的数据交换格式,非常适合于服务器与 JavaScript 的交互。本文将快速讲解 JSON 格式,并通过代码示例演示如何分别在客户端和服务器端进行 JSON 格式数据的处理。

         尽管有许多宣传关于 XML 如何拥有跨平台,跨语言的优势,然而,除非应用于 Web Services,否则,在普通的 Web 应用中,开发者经常为 XML 的解析伤透了脑筋,无论是服务器端生成或处理 XML,还是客户端用JavaScript 解析 XML,都常常导致复杂的代码,极低的开发效率。实际上,对于大多数 Web 应用来说,他们根本不需要复杂的 XML 来传输数据,XML 的扩展性很少具有优势,许多 AJAX 应用甚至直接返回 HTML 片段来构建动态 Web 页面。和返回 XML 并解析它相比,返回 HTML 片段大大降低了系统的复杂性,但同时缺少了一定的灵活性。

         现在, JSON 为 Web 应用开发者提供了另一种数据交换格式。让我们来看看 JSON 到底是什么,同 XML 或HTML 片段相比,JSON 提供了更好的简单性和灵活性。

    2、JSON语法

    和 XML 一样,JSON 也是基于纯文本的数据格式。由于 JSON 天生是为 JavaScript 准备的,因此,JSON 的数据格式非常简单,您可以用 JSON 传输一个简单的 String,Number,Boolean,也可以传输一个数组,或者一个复杂的 Object 对象。

    String,Number 和 Boolean 用 JSON 表示非常简单。例如,用 JSON 表示一个简单的 String “ abc ”,其格式为:

    "abc"

    除了字符 ",\,/ 和一些控制符(\b,\f,\n,\r,\t)需要编码外,其他 Unicode 字符可以直接输出。

    Boolean 类型表示为 true 或 false 。此外,JavaScript 中的 null 被表示为 null,注意,true、false 和 null 都没有双引号,否则将被视为一个 String 。

    JSON 还可以表示一个数组对象,使用 [] 包含所有元素,每个元素用逗号分隔,元素可以是任意的 Value,例如,以下数组包含了一个 String,Number,Boolean 和一个 null:

    ["abc",12345,false,null]

     Object 对象在 JSON 中是用 {} 包含一系列无序的 Key-Value 键值对表示的,实际上此处的 Object 相当于 Java 中的 Map<String, Object>,而不是 Java 的 Class 。注意 Key 只能用 String 表示。

    例如,一个 Address 对象包含如下 Key-Value:

    city:Beijing

     street:Chaoyang Road

     postcode:100025(整数)

     用 JSON 表示如下:

    {"city":"Beijing","street":" Chaoyang Road ","postcode":100025}

     其中 Value 也可以是另一个 Object 或者数组,因此,复杂的 Object 可以嵌套表示,例如,一个 Person 对象包含name 和 address 对象,可以表示如下:

    {"name":"Michael","address":

        {"city":"Beijing","street":" Chaoyang Road ","postcode":100025}

    }

     

    json格式的常见问题

    1)Jquery.ajax不能解析json对象,报Invalid JSON错误的原因和解决方法

     我们知道Invalid JSON错误导致的json对象不能解析,一般都是服务器返回的json字符串的语法有错误。这种情况下,我们只需要仔细的检查一下json就可以解决问题。

    下面说一下,最近在使用jquery 1.4中使用$.ajax()方法解析json对象遇到的问题。

     Json对象是:

     [{name:'二手房出售',infoCount:0,pageUrl:'/ershoufang'},{name:'二手房求购',infoCount:0,pageUrl:'/qiugou'},{name:'二手房装修',infoCount:0,pageUrl:'/esfzhuangxiu'},{name:'二手回收',infoCount:0,pageUrl:'/huishou'},{name:'二手摩托车',infoCount:0,pageUrl:'/motor'},{name:'二手汽车求购',infoCount:0,pageUrl:'/ershoucheqg'},{name:'二手汽车转让',infoCount:9,pageUrl:'/ershouche'},{name:'二手市场',infoCount:0,pageUrl:'/ershoushichang'}]

     不知道大家有没有发现这段json对象的问题。这样的写法在js脚本和jquery 1.4之前的版本都是没有问题的。因为在1.3及更早版本中,jQuery通过javascript的eval方法来解析json对象。在1.4中,jQuery使用了更严格的方法来解析json。所有的内容都必须使用双引号。

     这点从jQuery.parseJSON(json) 可以看出,parseJSON在文档中的解释是:

    接受一个JSON字符串,返回解析后的对象。

    传入一个畸形的JSON字符串会抛出一个异常。比如下面的都是畸形的JSON字符串: 
    {test: 1} ( test 没有包围双引号)
    {'test': 1} (使用了单引号而不是双引号)

    另外,如果你什么都不传入,或者一个空字符串、null或undefined,parseJSON都会返回 null 。

    凡是字符串都需要用双引号扩起来,数字,null,true,false不用而已

    来自 http://www.cnblogs.com/hyl8218/archive/2010/03/26/1694082.html

     2)传入的对象无效,应为“:”或“}”。

    还是传入的json字符串格式有问题,特殊字符如“引号需编码。

    .NET后台获取前台JQUERY AJAX传递JSON数组的问题 

    页面脚本:
    var people = [{ "UserName": "t1", "PassWord": "111111", "Sex": "男" }, { "UserName": "t2", "PassWord": "222222", "Sex": "女"}];

    我想把这个前端拼凑的JSON脚本发送后HANDLER后台。
    $("#btnSend").bind("click", function() {
      $.post("a.ashx", people, function(data, returnstatus) { }, "json");
      });

    后台应该如何接受啊,平时一般形式 都是CONTENT.Request【“参数”】 接受,但这个是JSON数组 如何接受呢?

    方案一:
    去www.json.org下载JSON2.js
    再调用JSON.stringify(JSONData)将JSON对象转化为JSON串。
    var people = [{ "UserName": "t1", "PassWord": "111111", "Sex": "男" }, { "UserName": "t2", "PassWord": "222222", "Sex": "女"}];

    再构造URL回传给服务器端:
    $("#btnSend").bind("click", function() {
      $.post("a.ashx", {xxxx:JSON.stringify(people)}, function(data, returnstatus) { }, "json");
      });

    服务器端解析传回的json字符串(注意格式问题

    服务器如何解析传回来的json数据?

    引用一段描述:

    Asp.net webapi Differences with MVC

    Here are some differences between MVC and WebAPI’s parameter binding:

    1. MVC only had model binders and no formatters. That’s because MVC would model bind over the request’s body (which it commonly expected to just be FormUrl encoded), whereas WebAPI uses a serializer over the request’s body.
    2. MVC buffered the request body, and so could easily feed it into model binding. WebAPI does not buffer the request body, and so does not model bind against the request body by default.
    3. WebAPI’s binding can be determined entirely statically based off the action signature types. For example, in WebAPI, you know statically whether a parameter will bind against the body or the query string. Whereas in MVC, the model binding system would search both body and query string.

     

    rc版的webapi参数绑定器分为两种:

     

    1.Model Binding
    2.Formatters 
    其中Model Binding仅从url中取值,这点是与mvc的model binding有区别的,formatters是从request的body中取值,并且是把整个body作为一个(不可为多个)对象解析为一个参数,后台需相对应的为前台传递的复杂类型定义一个对应的类。而mvc下的model binding系统会同时查询body和querystring下的数据并匹配。

     

    webapi是如何从这两种方式选择呢?

     

    1.默认情况下是根据参数的类型,如果参数为简单类型(字符串、整数、浮点、时间类型等),则使用model binding,如果是复杂类型(自定义的类,包括一个或多个字段)等,则用formatters

     

    2.可以给参数加上[FromBody]属性,则使用formatters

     

    3.可以给参数加上[ModelBinder]属性,则使用model binding,而且可以此属性允许你指定用自定义的绑定器,也可以使用[FromUri]属性来使用model binding

     

    4.特别注意一点,一个action上,只能有一个参数使用formatters,否则会在运行时抛出异常

     

    JSON.stringify 功能

     参见 http://technet.microsoft.com/zh-cn/sysinternals/cc836459(v=vs.94)

    序列化一个JavaScript 值对 JavaScript 对象表示法 (json) 文本。

    JSON.stringify(value [, replacer] [, space])

    JSON.parse 功能

    参加 http://technet.microsoft.com/zh-cn/sysinternals/cc836466(v=vs.94)

    将 JavaScript 对象生成JavaScript 值的表示法 (json) 文本。

    JSON.parse(text [, reviver])

     

    最后补充一个完整的json数据传递实例

    jquery ajax json传递数据浅析(注:使用的mvc下的model binding方式)

    来自 http://www.aichengxu.com/article/Javascript/664_7.html


    展开全文
  • 继续总结:Java经过Action后,怎么将action中返回的数据写到前台去 先了解下:HttpServletResponse对象 (1).Web服务器收到一个http请求,会针对每个请求创建一个HttpServletRequest和HttpServletResponse对象,向...

    继续总结:Java经过Action后,怎么将action中返回的数据写到前台去

    先了解下:HttpServletResponse对象

    (1).Web服务器收到一个http请求,会针对每个请求创建一个HttpServletRequest和HttpServletResponse对象,向客户端发送数据找HttpServletResponse,从客户端取数据找HttpServletRequest;

    (2).HttpServletResponse对象可以向客户端发送三种类型的数据:a.响应头b.状态码c.数据
    (3).自己去看HttpServletResponse的API
    (4).rsponse向前台返回数据:

    a.使用OutputStream向客户端写入中文:

        response.setHeader("Content-type","text/html;charset=UTF-8");//向浏览器发送一个响应头,设置浏览器的解码方式为UTF-8
        String data = "中国";
        OutputStream stream = response.getOutputStream();
        stream.write(data.getBytes("UTF-8"));

    b.使用Writer向客户端写入中文:

       response.setCharacterEncoding("UTF_8");//设置Response的编码方式为UTF-8
        response.setHeader("Content-type","text/html;charset=UTF-8");//向浏览器发送一个响应头,设置浏览器的解码方式为UTF-8,其实设置了本句,也默认设置了Response的编码方式为UTF-8,但是开发中最好两句结合起来使用
        //response.setContentType("text/html;charset=UTF-8");同上句代码作用一样
        PrintWriter writer = response.getWriter();
        writer.write("中国");
    


    看看企业一般怎么用:不管怎么用,无非就是封装成方法,向前台返回数据

    Action:

    public void searchModelIsUsed() {
    		<strong>HttpServletRequest req = ServletActionContext.getRequest();</strong>
    		boolean result1 = this.voucherTypeService.queryProductionMode();
    		if(result1==false){
    			//非生产模式则可修改模板
    			String result="is_PRODUCTION_MODE";
    			this.<strong>actionWrite</strong>("{success:'true',info:'" + result + "'}");
    		}else{
    			String vmId = req.getParameter("vmId");
    			boolean result = this.voucherTypeService.checkVoucherModelUsed(vmId);
    			this.actionWrite("{success:'true',info:'" + result + "'}");
    		}
    	}
    上面得到结果result,向前台返回显示数据用actionWrite

    actionWrite如下:

    	public void actionWrite(String result) {
    		if(result == null){
    			result = "";
    		}
    		HttpServletResponse resp = ServletActionContext.getResponse();
    		resp.setContentType("text/json;charset=UTF-8");
    		resp.setHeader("Cache-Control", "no-cache");
    		PrintWriter pw = null;
    		try {
    			pw = resp.getWriter();
    			pw.write(result);
    		} catch (IOException e) {
    			throw new EVoucherException("获取http写入流异常" + e.getMessage());
    		} finally {
    			if (pw != null) {
    				pw.close();
    			}
    		}
    	}

    可以看到actionWrite方法就是一个HttpServletResponse设置相关信息后利用PrintWriter向前台写数据

    在前台JS中,就是响应response后台传递过来的数据就OK。

    callback : function (options,success,response){
    	if(success){
    		
    		checkSessionOverdue(response.responseText);
    		var msg = Ext.JSON.decode(response.responseText);
    	var msgInfo = msg.info;
    	if(msgInfo == 'true'){
    		Ext.Msg.alert("系统提示", "当前模板已存在历史数据,只能修改模板名称跟启用日期!");
    		isAddVoucherModel = false;
    		refreshAddVoucherModelForm(false);
    	}else if(msgInfo=='is_PRODUCTION_MODE'){
    		isAddVoucherModel = true;
    		refreshAddVoucherModelForm(false);
    	}else{
    		isAddVoucherModel = true;
    		refreshAddVoucherModelForm(false);
    	}
    		
    	}
    }





    展开全文
  • SpringMVC实现全局异常处理器

    万次阅读 多人点赞 2018-09-29 18:23:26
    通过 @ControllerAdvice 注解,我们可以在一个地方对所有 @Controller 注解的控制器进行管理。 注解了 @ControllerAdvice 的类的方法可以使用 @ExceptionHandler、 @InitBinder、 @ModelAttribute 注解到方法上,...
  • 我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况。Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容。 启动...
  • Java Web前端到后台常用框架介绍

    万次阅读 多人点赞 2016-03-18 11:46:49
    一、SpringMVChttp://blog.csdn.net/evankaka/article/details/45501811Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,...
  • 使用redis进行缓存

    万次阅读 2017-07-27 17:12:35
    前台系统访问后台管理系统,如果要使用缓存,那么缓存逻辑一定放在后台系统。且要放在业务层。 当使用redis缓存时,要注意,在业务代码(service类)中,首先先从redis中去获取,然后return。但是这里要用try-catch...
  • 用ajax请求时报post 400 (Bad Request)的异常前台js参数JSON.stringify(data),后台controller 中@RequestBody XX xx(javabean)接收参数。 通常发生400时,即使在后台方法上设置断点,但因400是参数由json转换成...
  • 当以上三个条件都满足时浏览器会抛出跨域请求异常(记住是浏览器抛出的异常,和服务端没太大关系),在讲跨域请求解决方案前先了解几个问题。 1 http请求中,哪些是常见的简单请求,哪些是非简单请求 常见的简单...
  • mock平台架构及实现(持续更新)

    万次阅读 2016-07-10 13:43:18
    mock平台架构及实现
  • Jackson报错org.codehaus.jackson.map.JsonMappingException /* Markdown.css */ /* Authors: Kevin Burke: http://kev.inburke.com/, modified by Evan Wondrasek */ /* https://bitbucket.org/kevinburke/ma
  • SpringBoot2.x【二】快速开发插件与API规范 萌新:小哥,我在实体类写了那么多get/set方法,看着很迷茫 小哥:那不是可以自动生成吗? 萌新:虽然可以自动生成,但是如果我要修改某个变量的数据类型,我岂不是还要...
  • 电子商务网站互联网安全防御攻略

    万次阅读 多人点赞 2015-09-05 16:57:56
    电子商务网站,互联网的安全防御相当重要,尤其是牵扯到支付这一块的。本文总结了一些比较通用的 web 安全防御常识,供大家参考一下,也希望可以和关心这一块的同行一起讨论一下这方面的话题。
  • Bearer Token的相关定义与使用方法

    万次阅读 2016-09-05 18:20:33
    原文地址:...正因如此,服务器端的组建也正正在从传统的任务中解脱,转而变的更像APIAPI使得传统的前端和后端的概念解耦。开发者可以脱离前端,独立的开发后端,在测试上获得更大的便利。这种途径也使
  • 做为一个程序员可能在学习技术,了解行业新动态,解决问题时经常需要阅读英文的内容;...这里就分享一下我的研究学习过程,如何使用Python调用REST API打造自己的在线翻译工具,并演示如何把它发布到云平台上
  • 由于前端代码调用后端接口,需要使用响应状体码告知前端登录异常(401)和权限验证不通过(403)。前端拿到对应的状态码会做出相应的处理。 上述的登录验证和权限验证,后端采用Spring拦截器技术实现。为了返回指定...
  • jsp页面显示空白的原因

    千次阅读 2017-11-17 11:46:06
    3、 lib中的jsp-api.jar在作怪,这个jar已经不知道是从何而来的了更不知道版本号,好像是从Spring2.0m5的 dependency lib中拷过来的。可能是里面的jsp-api和我的tomcat5.5不太兼容吧  4、一个查询的jsp页面,点击...
  • 微信支付.NET版开发总结(JS API),好多坑,适当精简,希望后来做的人少走弯路。
  • Guns V3.0简介

    万次阅读 2017-10-24 20:34:05
    Guns V3.0介绍Guns基于Spring Boot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + mybatis-plus + beetl!Guns项目代码简洁,注释丰富,上手容易,同时Guns包含...Guns v3.0新增REST API服务,提供对接服务端接
1 2 3 4 5 ... 20
收藏数 9,844
精华内容 3,937
关键字:

webapi 异常信息返回前台了