AngularJS 2调用.net core WebAPI的几个坑

2023-11-16

前几天,按照AngularJS2的英雄指南教程走了一遍,教程网址是http://origin.angular.live/docs/ts/latest/tutorial/

在步骤完成后,又更进一步,在英雄增删改的时候,直接调用.net core的WebApi来实现后台数据的操作,替换教程中的模拟WebApi方式。在替换.net core WebApi时,还是遇到了一些坑的,这里记录一下。

先来看一下WebApi和AngularJS的源代码:

WebApi

 1     [Route("api/[controller]")]
 2     public class ValuesController : Controller
 3     {
 4         private List<Hero> heroes;
 5 
 6         public ValuesController()
 7         {
 8             heroes = GetHeroes()
 9 
10         }
11 
12         [HttpGet]
13         public IEnumerable<Hero> Get()
14         {
15             return heroes;
16         }
17 
18         [HttpGet("{id}")]
19         public Hero Get(int id)
20         {
21             return heroes.Single(h => h.Id == id);
22         }
23 
24         [HttpGet]
25         [Route("GetList")]
26         public IEnumerable<Hero> GetList(string key)
27         {
28             return heroes.Where(h => h.Name.Contains(key));
29         }
30 
31         [HttpPost]
32         public void Post([FromBody]Hero info)
33         {
34             Hero hero = new Hero();
35 
36             hero.Id = heroes.Max(h => h.Id) + 1;
37             hero.Name = info.Name;
38 
39             AddHeroes(hero);
40         }
41 
42         [HttpPut("{id}")]
43         public void Put(int id, [FromBody]Hero hero)
44         {
45             Hero x = heroes.Single(h => h.Id == id);
46 
47             x.Name = hero.Name;
48 
49             UpdateHeroes(x);
50         }
51 
52         [HttpDelete("{id}")]
53         public void Delete(int id)
54         {
55             Hero hero = heroes.Single(h => h.Id == id);
56             RemoveHeroes (hero);
57         }
58 }
View Code

 

AngularJS

 1     getHeroes(): Promise<Hero[]> {
 2         return this.http.get(this.heroUrl).toPromise().then(response => response.json() as Hero[]).catch(this.handleError);
 3     }
 4 
 5     getHero(id: number): Promise<Hero> {
 6         return this.getHeroes().then(heroes => heroes.find(hero => hero.id === id));
 7     }
 8 
 9     getHeroesSlowly(): Promise<Hero[]> {
10         return new Promise<Hero[]>(resolve =>
11             setTimeout(resolve, 2000)) // delay 2 seconds
12             .then(() => this.getHeroes());
13     }
14 
15     updateHero(hero: Hero): Promise<Hero> {
16         const url = `${this.heroUrl}/${hero.id}`;
17         return this.http
18             .put(url, JSON.stringify(hero), { headers: this.headers })
19             .toPromise()
20             .then(() => hero)
21             .catch(this.handleError);
22     }
23 
24     addHero(heroName: string): Promise<Hero> {
25         return this.http
26             .post(this.heroUrl, JSON.stringify({ name: name }), { headers: this.headers })
27             .toPromise()
28             .then(response => response.json())
29             .catch(this.handleError);
30     }
31 
32     deleteHero(heroId: number): Promise<void> {
33         const url = `${this.heroUrl}/${heroId}`;
34         return this.http
35             .delete(url, { headers: this.headers })
36             .toPromise()
37             .then(() => null)
38             .catch(this.handleError);
39     }
40 
41     search(term: string): Observable<Hero[]> {
42         return this.http.get(`${this.heroUrl}/GetList?key=${term}`).map((r: Response) => r.json() as Hero[]);
43     }
44 
45     private handleError(error: any): Promise<any> {
46         console.error('An error occurred', error); // for demo purposes only
47         return Promise.reject(error.message | error);
48     }
View Code

 

一、跨域访问(Cors)问题

在建好WebApi站点,启动运行,一切正常。我们仅显示前两个Action,结果如下:

然而,在AngularJS客户端,出现了问题,界面没有任何英雄出现。

再查Chrome的控制台,发现了问题所在,WebApi的Access-Control-Allow-Origin没有开,也就是跨域访问不通过。

跨域访问,就是JS访问其他网址的信息。例如这里的AngularJS的

1     getHeroes(): Promise<Hero[]> {
2         return this.http.get(this.heroUrl).toPromise().then(response => response.json() as Hero[]).catch(this.handleError);
3     }

方法中,调用heroUrl(WebApi网址)。AngularJS的网址是http://localhost:3000/,而WebApi的网址是http://localhost:5000/api/values。只要协议、域名、端口有任何一个不同,都被当作是不同的域。默认情况下是不支持直接跨域访问的。为了在WebiApi中增加跨域访问,我们要在WebApi的Startup.cs中打开Access-Control-Allow-Origin:

1         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
2         {
3             app.UseCors(builder =>
4             {
5                 builder.AllowAnyOrigin();
6             });
7 
8             app.UseMvc();
9         }

 

现在程序访问正常。

我们查看AngularJS网站的network情况,在values的headers—Response Headers中有Access-Control-Allow-Origin: *的字样,这样就解决了前面出现的"No Access-Control-Allow-Origin header is present…"错误。

 

再继续测试,又出现问题了,这次是在更新时

错误信息如下:

我们都已经打开Access-Control-Allow-Origin,怎么还报错:"No Access-Control-Allow-Origin header is present…"?我们回过来看AngularJS,调用的是Update:

1     updateHero(hero: Hero): Promise<Hero> {
2         const url = `${this.heroUrl}/${hero.id}`;
3         return this.http
4             .put(url, JSON.stringify(hero), { headers: this.headers })
5             .toPromise()
6             .then(() => hero)
7             .catch(this.handleError);
8     }

 

对应WebApi,这次调用的是Put方法

1         [HttpPut("{id}")]
2         public void Put(int id, [FromBody]Hero hero)
3         {
4             Hero x = heroes.Single(h => h.Id == id);
5 
6             x.Name = hero.Name;
7 
8             UpdateHeroes(hero.Name);
9         }

是不是由于Method不对啊,以前都是Post、Get,这次是Put。趁早,一不做,二不休,在WebApi的Startup.cs中,写成如下:

 1         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 2         {
 3             app.UseCors(builder =>
 4             {
 5                 builder.AllowAnyOrigin();
 6                 builder.AllowAnyHeader();
 7                 builder.AllowAnyMethod();
 8             });
 9 
10             app.UseMvc();
11         }

 

允许所有Origin、Header和Method。这次彻底搞定,运行正常。

二、Update方法,必须使用类

其实上面Update时,还是遇到了部分问题的。就是按照最开始的程序,我们在WebApi的Put方法中,传入的是英雄名称name,而不是Hero对象。

1         [HttpPut("{id}")]
2         public void Put(int id, [FromBody]string name)
3         {
4             Hero x = heroes.Single(h => h.Id == id);
5 
6             x.Name = name;
7 
8             UpdateHero(x);
9         }

同时AngularJS中如下:

1     updateHero(hero: Hero): Promise<Hero> {
2         const url = `${this.heroUrl}/${hero.id}`;
3         return this.http
4             .put(url, JSON.stringify({name: name}), { headers: this.headers })
5             .toPromise()
6             .then(() => hero)
7             .catch(this.handleError);
8     }

 

在程序运行时,我们修改第13号英雄:

查看network,提交也是name: "Bombasto1111"。

然而,在WebApi中,调试情况下:

Id没有问题,但是name是null。[FromBody]要求前台传入的是Json串,然后提交到Action中。这时,Angular传入的是{name: "Bombasto1111"},通过FromBody转换后,是一个object,而不是一个string,因此name的值是null。

如果想用string name方式,AngularJS就要写成:

1     updateHero(hero: Hero): Promise<Hero> {
2         const url = `${this.heroUrl}/${hero.id}`;
3         return this.http
4             .put(url, JSON.stringify(hero.name), { headers: this.headers })
5             .toPromise()
6             .then(() => hero)
7             .catch(this.handleError);
8     }

 

再看network

WebApi调试状态如下图,name有值,一切搞定。

 

也可以使用Hero作为参数的方式,如同我们文档最开始提供的代码一样。

1     updateHero(hero: Hero): Promise<Hero> {
2         const url = `${this.heroUrl}/${hero.id}`;
3         return this.http
4             .put(url, JSON.stringify(hero), { headers: this.headers })
5             .toPromise()
6             .then(() => hero)
7             .catch(this.handleError);
8     }

 

        [HttpPut("{id}")]
        public void Put(int id, [FromBody]Hero hero)
        {
            Hero x = heroes.Single(h => h.Id == id);

            x.Name = hero.Name;

            UpdateHeroes(x);
        }

 

 

三、路由改变

我们在做Hero Search的时候,又要在后台WebApi中编写按照关键字查询的方法

1         [HttpGet]
2         public IEnumerable<Hero> GetList(string key)
3         {
4             return heroes.Where(h => h.Name.Contains(key));
5         }

 

如果仅仅这样写,整个WebApi都不好用了。在调用Get时,出现了喜闻乐见的500错误。

而调用Get(int id)方法,就是localhost:5000/api/values/11时,一切正常。这是为什么呢?

因为按照微软的方式,如果有多个相同Method(例如HttpGet)的方法,WebApi路由就没法区分了。这里,Get()和GetList(string key)都是[HttpGet],路由都是localhost:5000/api/values。而Get(int id)方法由于写的是[HttpGet("{id}")],网址是localhost:5000/api/values/11,与Get()路由不同。因此,为了解决Get()和GetList(string key),我们在getlist方法上增加指定路由的方式。例如这里就是

1         [HttpGet]
2         [Route("GetList")]
3         public IEnumerable<Hero> GetList(string key)
4         {
5             return heroes.Where(h => h.Name.Contains(key));
6         }

 

在AngularJS中,就可以使用localhost:5000/api/values/GetList?key=XXXX的方式调用,程序如下:

1     search(term: string): Observable<Hero[]> {
2         return this.http.get(`${this.heroUrl}/GetList?key=${term}`).map((r: Response) => r.json() as Hero[]);
3     }

 

当然了,如果想更进一步,需要再修改整个路由方式,增加Action。这就需要在Controller上增加[Route("api/[controller]/[action]/")]的写法,并且将Action的[Route]删除。

[Route("api/[controller]/[action]/")]

public class ValuesController : Controller

 

这次是真的解决了。

转载于:https://www.cnblogs.com/BenDan2002/p/6256161.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AngularJS 2调用.net core WebAPI的几个坑 的相关文章

  • VBA / HTML / jQuery 选择自动完成 - 在列表中选择

    我正在尝试使用 Excel 中的 VBA 在网站的列表中选择一个值 这不是一个 正常列表 该网站使用 jQuery 选择自动完成 如下所示 example http davidwalsh name demo jquery chosen ph
  • Jquery从下拉列表中获取所选值的id

    我有一个下拉列表 可以从数据库获取值 如下所示 get getJobs function jobs seljobs jobs var i 0 jobs forEach function n alert job id n id 32 67 4
  • Leaflet js虚构地图

    我是 Leaflet 的新手 我想了解如何创建完全交互式的虚构地图 我有一张图像想要转换为传单地图 该图像基本上像图表一样具有许多连接和点 我想首先将该图像转换为地图 能够将鼠标悬停在这些点上 突出显示它们并显示有关它们的信息 并且还可以在
  • 在闪亮的数据表中为每个单元格显示工具提示或弹出窗口?

    有没有什么方法可以为 r闪亮数据表中的每个单元格获取工具提示 有很多方法可以获取悬停行或列 但我找不到一种方法来获取行和列索引并为每个单元格显示不同的悬停工具提示 任何人都可以修改以下代码吗 library shiny library DT
  • javascript中按tab键时如何调用函数?

    我有一个这样的功能 function whenEmpty field if field value field style backgroundColor ffcccc alert Please fill the field field f
  • 使用 json_encode() 函数在 PHP 数组中生成 JSON 键值对

    我正在尝试以特定语法获取 JSON 输出 这是我的代码 ss array 1 jpg 2 jpg dates array eu gt 59 99 us gt 39 99 array1 array name gt game1 publishe
  • 通过 node-http-proxy 保留基于 cookie 的会话

    我有一个简单的基于 Express 的 Node js Web 服务器 用于开发 JavaScript 应用程序 我将服务器设置为使用 node http proxy 来代理应用程序向在不同域和端口上运行的 Jetty 服务器发出的 API
  • JavaScript 中数组的 HTML 数据列表值

    我有一个简单的程序 它必须从服务器上的文本文件中获取值 然后将数据列表填充为输入文本字段中的选择 为此 我想要采取的第一步是我想知道如何动态地将 JavaScript 数组用作数据列表选项 我的代码是
  • 如果链接包含特定文本,jQuery 将类添加到 href

    我的网站上的列表中有一些动态填充的链接 这些链接链接到文件 是否可以使用 jQuery 查看文件名是否以 pdf 结尾 并在 href 或类似的链接文本以 mp3 结尾时添加一个类 例如 我的列表中有以下链接 文件1 pdf 歌曲1 mp3
  • Typeahead.js substringMatcher 函数说明

    我只是在做一些研究Typeahead js这是一个非常酷的图书馆 感谢文档 我已经成功地获得了一个基本的示例 该文档也非常好 但是我试图弄清楚以下代码块实际上在做什么 var substringMatcher function strs r
  • 如何使JavaScript函数在Eclipse“大纲视图”中可见?

    我有这样的代码 但如果它在匿名函数中定义 则无法打开函数大纲 类没有问题 我该如何概述something2 请分享一些提示 我可以将所有函数标记为构造函数 但这是无效的方法 start of track event required deb
  • 淡出和循环一组 div 的最佳方式

    假设我有以下 div div class a You are funny div div class b You are smart div div class c You are cool div 最好的展示方式是什么div a持续 5
  • 将 javascript 整数转换为字节数组并返回

    function intFromBytes x var val 0 for var i 0 i lt x length i val x i if i lt x length 1 val val lt lt 8 return val func
  • Twitter 嵌入时间轴小部件

    我继续下载http platform twitter com widgets js http platform twitter com widgets js And the http platform twitter com embed t
  • Chartjs刻度标签位置

    尝试让 Y 轴刻度标签看起来像image https i stack imgur com XgoxX png 位于秤顶部且不旋转 缩放选项当前如下所示 scales yAxes id temp scaleLabel display true
  • 类型“typeof import("/home/kartik/Desktop/Ecommerce/ecommerce/node_modules/firebase/index")”上不存在属性“auth”。 TS(2339)

    我是 FireBase 的初学者 我正在尝试使用 Angular 通过 FireBase 实现 Google 登录 我在 auth 时收到上述错误 我特此附上login component ts和package json package l
  • 数据表日期范围过滤器

    如何添加日期范围过滤器 like From To 我开始进行常规搜索和分页等工作 但我不知道如何制作日期范围过滤器 我正在使用数据表 1 10 11 版本 My code var oTable function callFilesTable
  • Jquery - 通过在字符串中构建 id 的 id 获取元素

    我在使用 jquery 元素时遇到问题 我正在 var 中构造名称 例如 var myId myGotId myId attr title changed myId 返回空 我想通过 id 获取我的元素 但动态构建我的 Id 连接字符串 编
  • 防止文本区域出现新行

    我正在开发聊天功能 使用 Vue 并使用文本区域作为输入 以便溢出换行 并且对于编写较长消息的用户来说更具可读性 不幸的是 当用户按下 Enter 键并提交时 光标会在提交之前移动到新行 从而使用户体验感觉不佳 关于如何使用普通 Javas
  • 如何在 gulp.src 中使用基本正则表达式?

    我正在尝试选择两个文件gulp src highcharts js and highcharts src js 当然 我知道我可以使用数组表达式显式添加这两个表达式 但出于学习目的 我尝试为它们编写一个表达式 我读过可以使用简单的正则表达式

随机推荐

  • Windows server 服务器com安全编辑限制选项灰色

    在一次Windows server 系统运维中 项目实施方搭建OPC时遇到了com 安全编辑限制选项灰色的问题 当时百度查找了很多但是也没查到 但是能确定应该是组策略和注册表中用户administrator权限不够的问题 查找资料中发现Dc
  • 2021->2022

    也就随便写写了 记得去年的年终和期望目标 我写了好多个方面的自我剖析 可能大概有三四千字吧 再回去看看 还是水了一些 这很正常 大多数人都是这样的 况且我比较佛系 复盘还是要的 期望还是要提的 虽然明知一年过后 可能达成的不多 但这也是一次
  • 医疗知识中台白皮书

    该白皮书显示 医疗行业平均医护人员供给不足 优质医疗资源过于聚集 医疗资源质量短期难以大幅提高等问题突出 与此同时 遵循医疗逻辑的智能化开放平台 医疗知识中台 正在成为解决这一难题的突破口 关注公众号 互联互通社区 回复 ZTZL053 获
  • 通用网关接口(摘录)

    维基百科 自由的百科全书 通用网关接口 Common Gateway Interface CGI 是一种重要的互联网技术 可以让一个客户端 从网页浏览器向执行在 Web 服务器 上的程序 请求数据 CGI 描述了客户端和这个程序之间传输数据
  • 【Python-利用动态二维码传输文件(四)】使用pyautogui库录屏(连续截图),然后利用OpenCV逐张读取截图,识别当中的二维码信息,并把信息重组成原文件

    程序示意图 目录 一 使用pyautogui库 对电脑屏幕进行录屏 二 使用OpenCV库对100帧截图进行识别 并与原29帧二维码图片内含信息进行比对 三 把获取的100帧二维码信息去重 并保持原来顺序 重组成原来的文件 四 小结和完整代
  • Java前后端分离动态国际化(动态配置扩展性高)

    介绍 主要是针对前后端分离场景国际化系统设计 亮点 1 动态国际化配置 2 可维护性 3 国际化数据池化 性能高 4 后端数据内容动态国际化 5 提供前台动态国际化数据 6 后台异常国际化处理 7 可动态添加国际化的语种 8 国际化配置集中
  • React中路由组件的lazyLoad

    1 通过React的lazy函数配合import 函数动态加载路由组件 gt 路由组件代码会被分开打包 const Login lazy gt import pages Login 2 通过
  • 生成一定相关性的二元正态分布

    生成一定相关性的二元正态分布 摘要 二元正态分布 二元正态分布概率密度函数 二元正态分布随机数的生成 程序实现 多元正态分布的情况 生成服从 N
  • 【http】10,000 milliseconds timeout on connection http-outgoing-0 [ACTIVE]

    1 概述 本日使用http远程连接获取远程接口信息报错 10 000 milliseconds timeout on connection http outgoing 0 ACTIVE 022 12 23 09 54 15 181 ERRO
  • C潜规则篇之防止重定义

    C程序编译时常出现类似xxx redefinition错误 除了模块间的命名冲突 命名污染及static 问题多数与头文件管理有关 大型C工程的头文件管理很麻烦 C源文件往往包含很多头文件 头文件又包含其他头文件 形成复杂的嵌套包含 C没有
  • Android 逆向工程,反编译心得

    前言 apk的反编译是我们在Android开发中绕不开的一个坎 对于反编译这门技术 我们应该抱着学习的态度 学的越多 也越能防备别人反编译我们 这就是所谓的知己知彼吧 哈哈 需要准备的工具 Apktool 解包和重新打包都需要它 dex t
  • 在什么情况下、使用python类的使用-使用Python编程时的10个注意事项

    原标题 使用Python编程时的10个注意事项 1 初始变化量 在Python里 一个表达式中的名字在它被赋值之前是没法使用的 这是有意而为的 这样能避免一些输入失误 同时也能避免默认究竟应该是什么类型的问题 0 None 记住把计数器初始
  • iOS Provisioning Profile(Certificate)与Code Signing详解

    引言 关于开发证书配置 Certificates Identifiers Provisioning Profiles 相信做iOS开发的同学没少被折腾 对于一个iOS开发小白 半吊子 比如像我自己 抑或老兵 或多或少会有或曾有过以下不详 疑
  • “Intel VT-x处于禁用状态”如何处理

    在安排虚拟机时 出现Intel VT x处于禁用状态时 第一步 进入bios页面 就是重装系统的那个页面 有的电脑是F1 F2 F10 F12 具体多少上网查查就行了 将intel Virtual Technology改成enabled 第
  • 回调函数&&回调机制

    所谓回调 定义是 一个方法的指针传递给事件源 当某一事件发生时用来调用这个方法 比如客户程序C调用服务程序S中的某个函数A 然后S又在某个时候反过来调用C中的某个函数B 对于C来说 这个B便叫做回调函数 例如Win32下的窗口过程函数就是一
  • 如何写CSDN博客

    如何写CSDN博客 我这里使用Typora软件先将博客写好 这个软件可以去应用商城下载 写好以后我们打开CSDN博客网页 找到创作中心的写文章 然后我们会找到导入 找到我们要选择发布的博客 导入后我们发现博客里的图片图片导入失败 我们需要手
  • Kappa 与 Lambda 架构介绍与对比

    Lambda 架构 Lambda 架构由Storm的作者Nathan Marz提出 其设计目的在于提供一个能满足大数据系统关键特性的架构 包括高容错 低延迟 可扩展等 其整合离线计算与实时计算 融合不可变性 读写分离和复杂性隔离等原则 可集
  • Ubuntu mysql配置root用户远程登录

    查看mysql默认密码登录数据库 cat etc mysql debian cnf 查看root用户数据 use mysql select User Host authentication string from user 增加root用户
  • Android中Context详解 ---- 你所不知道的Context

    大家好 今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友 Context类 说它熟悉 是应为我们在开发中 时刻的在与它打交道 例如 Service BroadcastReceiver Activity等都会利用到Context的相关方法
  • AngularJS 2调用.net core WebAPI的几个坑

    前几天 按照AngularJS2的英雄指南教程走了一遍 教程网址是http origin angular live docs ts latest tutorial 在步骤完成后 又更进一步 在英雄增删改的时候 直接调用 net core的W