- Angular 教程
- Angular - 首页
- Angular - 概述
- Angular - 功能
- Angular - 优点与缺点
- Angular 基础
- Angular - 环境搭建
- Angular - 第一个应用
- Angular - MVC 架构
- Angular 组件
- Angular - 组件
- Angular - 组件生命周期
- Angular - 视图封装
- Angular - 组件交互
- Angular - 组件样式
- Angular - 嵌套组件
- Angular - 内容投影
- Angular - 动态组件
- Angular - 元素
- Angular 模板
- Angular - 模板
- Angular - 文本插值
- Angular - 模板语句
- Angular - 模板中的变量
- Angular - SVG 作为模板
- Angular 数据绑定
- Angular - 数据绑定及其类型
- Angular - 数据绑定
- Angular - 事件绑定
- Angular - 属性绑定
- Angular - 属性绑定
- Angular - 类和样式绑定
- Angular 指令
- Angular - 指令
- Angular - 内置指令
- Angular 管道
- Angular - 管道
- Angular - 使用管道转换数据
- Angular 依赖注入
- Angular - 依赖注入
- Angular HTTP 客户端编程
- Angular - 服务
- Angular - HTTP 客户端
- Angular - 请求
- Angular - 响应
- Angular - GET 请求
- Angular - PUT 请求
- Angular - DELETE 请求
- Angular - JSON-P
- Angular - 使用 HTTP 进行 CRUD 操作
- Angular 路由
- Angular - 路由
- Angular - 导航
- Angular - Angular Material
- Angular 动画
- Angular - 动画
- Angular 表单
- Angular - 表单
- Angular - 表单验证
- Angular Service Workers 和 PWA
- Angular - Service Workers 和 PWA
- Angular 测试
- Angular - 测试概述
- Angular NgModule
- Angular - 模块介绍
- Angular 高级
- Angular - 身份验证和授权
- Angular - 国际化
- Angular - 可访问性
- Angular - Web Workers
- Angular - 服务器端渲染
- Angular - Ivy 编译器
- Angular - 使用 Bazel 构建
- Angular - 向后兼容性
- Angular - 响应式编程
- Angular - 指令和组件之间共享数据
- Angular 工具
- Angular - CLI
- Angular 其他
- Angular - 第三方控件
- Angular - 配置
- Angular - 显示数据
- Angular - 装饰器和元数据
- Angular - 基本示例
- Angular - 错误处理
- Angular - 测试和项目构建
- Angular - 生命周期钩子
- Angular - 用户输入
- Angular - 新功能?
- Angular 有用资源
- Angular - 快速指南
- Angular - 有用资源
- Angular - 讨论
Angular - JSON-P
HttpClient jsonp() 方法
JSONP 是一种特殊的技术,用于绕过 Web 浏览器强制执行的跨域 (CORS) 策略。通常情况下,浏览器只支持同一个域内网站的 AJAX 调用。要支持对另一个域的 AJAX 调用,CORS 策略必须在服务器端和客户端(浏览器)都启用。
与其启用 CORS 策略,服务器可以发送 JSONP 格式的响应。JSONP 格式基本上是用回调函数包装的 JSON。浏览器将从服务器获取响应并将其作为脚本执行。回调函数将获取响应并执行必要的业务逻辑。
服务器可以通过用回调函数(例如 mycallback)包装 JSON 格式的响应将其转换为 JSONP 格式,如下所示:
mycallback( { ... json data ... })
这里:
mycallback 是浏览器(客户端)发送的函数名称。
jsonp() 是 HttpClient 类中可用的方法,用于使用 jsonp 技术请求服务器。它类似于 get() 方法,但增加了一个选项,用于设置服务器用来获取回调函数的查询参数的名称。Angular 将自动生成一个函数来解析客户端的 JSON。然后,它将向 url 添加新的查询参数。查询参数的名称将是在 jsonp 调用中设置的名称。查询参数的值是 Angular 自动生成的函数的名称。
jsonp() 方法的签名
jsonp() 方法的签名如下:
jsonp(<url as string>, <callback>)
url 表示要请求的资源的 URI。
callback 表示在 jsonp 服务器调用后要调用的回调函数名称(将自动生成)。
演示 jsonp 方法的简单代码如下:
let jsonp_req = this.http.jsonp<Expense[]>('https://127.0.0.1:8000/api/jsonp/expense', 'callback'); jsonp_req.subscribe(data => this.expenses = data);
这里:
this.http 是 HttpClient 实例。
jsonp() 是用于请求服务器的方法。它不会直接请求服务器。相反,它返回一个 Observable,可以通过订阅它来请求服务器,并在订阅函数中获取实际的响应。
https://127.0.0.1/api/jsonp/expense 是资源的 URI(统一资源标识符)
Angular 将自动生成一个函数,例如 ng_jsonp_callback_0,并使用 jsonp() 函数的第二个参数将其附加到请求 url。
https://127.0.0.1:8000/api/jsonp/expense?callback=ng_jsonp_callback_0
工作示例
为了实现 HTTP 客户端-服务器通信,我们需要设置一个 Web 应用程序并公开一组 Web API。客户端可以请求 Web API。让我们创建一个示例服务器应用程序,Expense API App,为支出提供 CRUD REST API(主要是 jsonp 请求)。
步骤 1:转到您喜欢的 workspace,如下所示:
cd /go/to/your/favorite/workspace
步骤 2:创建一个新文件夹 expense-rest-api 并进入该文件夹
mkdir expense-rest-api && cd expense-rest-api
步骤 3:使用 npm 命令提供的 init 子命令创建一个新应用程序,如下所示:
npm init
上述命令会提出一些问题,请使用默认答案回答所有问题。
步骤 4:安装 express 和 cors 包以创建基于节点的 Web 应用程序。
npm install express cors --save
步骤 5:安装 sqlite 包以将支出存储在基于 sqlite 的数据库中
npm install sqlite3 --save
步骤 6:创建一个新文件 sqlitedb.js,并添加以下代码以使用支出表和示例支出条目初始化数据库。支出表将用于存储支出项目
var sqlite3 = require('sqlite3').verbose() const DBSOURCE = "expensedb.sqlite" let db = new sqlite3.Database(DBSOURCE, (err) => { if (err) { console.error(err.message) throw err }else{ console.log('Connected to the SQLite database.') db.run(`CREATE TABLE IF NOT EXISTS expense ( id INTEGER PRIMARY KEY AUTOINCREMENT, item text, amount real, category text, location text, spendOn text, createdOn text )`, (err) => { if (err) { console.log(err); }else{ var insert = 'INSERT INTO expense (item, amount, category, location, spendOn, createdOn) VALUES (?,?,?,?,?,?)' db.run(insert, ['Pizza', 10, 'Food', 'KFC', '2020-05-26 10:10', '2020-05-26 10:10']) db.run(insert, ['Pizza', 9, 'Food', 'Mcdonald', '2020-05-28 11:10', '2020-05-28 11:10']) db.run(insert, ['Pizza', 12, 'Food', 'Mcdonald', '2020-05-29 09:22', '2020-05-29 09:22']) db.run(insert, ['Pizza', 15, 'Food', 'KFC', '2020-06-06 16:18', '2020-06-06 16:18']) db.run(insert, ['Pizza', 14, 'Food', 'Mcdonald', '2020-06-01 18:14', '2020-05-01 18:14']) } } ); } }); module.exports = db
步骤 7:打开 index.js 并更新以下代码:
var express = require("express") var cors = require('cors') var db = require("./sqlitedb.js") var app = express() app.use(cors()); var bodyParser = require("body-parser"); app.use(express.urlencoded({ extended: true })); app.use(express.json()); var HTTP_PORT = 8000 app.listen(HTTP_PORT, () => { console.log("Server running on port %PORT%".replace("%PORT%", HTTP_PORT)) }); app.get("/", (req, res, next) => { res.json({ "message": "Ok" }) }); app.get("/api/jsonp/expense", (req, res, next) => { var sql = "select * from expense" var params = [] db.all(sql, params, (err, rows) => { if (err) { res.status(400).json({ "error": err.message }); return; } res.jsonp(rows) }); }); app.use(function (req, res) { res.status(404); });
在这里,代码将创建以下六个提到的 REST API 端点。
/ 端点返回 OK 消息,以确保应用程序正常工作。
/api/jsonp/expense 端点以 jsonp 格式返回数据库中所有可用的支出项目。
步骤 8:运行应用程序,如下所示:
node index.js
步骤 9:要测试应用程序并确保其正常工作,请打开浏览器并访问 https://127.0.0.1:8000/。如果应用程序正常工作,则应返回以下消息。
{ "message": "Ok" }
让我们创建一个可工作的 Angular 示例,以使用 HttpClient 服务类和 get() 方法从上述服务器应用程序获取所有支出项目。
步骤 1:通过运行 ng new 命令创建一个新的 Angular 应用程序,如下所示:
ng new my-http-app
启用 Angular 路由和 CSS,如下所示:
? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? CSS
步骤 2:通过在模块配置文件 (app.module.ts) 中导入 HttpClientModule 来启用应用程序中的 HTTP 通信。
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HttpClientModule, HttpClientJsonpModule} from '@angular/common/http'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, HttpClientJsonpModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
这里:
从 @angular/common/http 模块导入 HttpClientModule 和 HttpClientJsonpModule。
将 HttpClientModule 添加到 @NgModule 配置的 imports 部分。
步骤 3:创建一个新的接口 Expense 来表示我们的支出项目。
interface Expense { id: Number, item: String, amount: Number, category: String, location: String, spendOn: Date } export default Expense;
步骤 4:创建一个新的组件 ListExpenses 来显示来自服务器的支出项目。
ng generate component ListExpenses
它将创建如下所示的组件:
CREATE src/app/list-expenses/list-expenses.component.css (0 bytes) CREATE src/app/list-expenses/list-expenses.component.html (28 bytes) CREATE src/app/list-expenses/list-expenses.component.spec.ts (602 bytes) CREATE src/app/list-expenses/list-expenses.component.ts (229 bytes) UPDATE src/app/app.module.ts (581 bytes)
步骤 5:将我们的新组件包含到 App 根组件的视图 app.component.html 中,如下所示:
<app-list-expenses></app-list-expenses> <router-outlet></router-outlet>
步骤 6:通过构造函数将 HttpClient 注入 ListExpenses 组件,如下所示:
import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-list-expenses', templateUrl: './list-expenses.component.html', styleUrls: ['./list-expenses.component.css'] }) export class ListExpensesComponent { constructor(private http: HttpClient) { } }
步骤 7:实现 OnInit 生命周期钩子,以便在 ListExpenses 组件初始化后请求服务器获取支出。
export class ListExpensesComponent implements OnInit{ constructor(private http: HttpClient) { } ngOnInit(): void { } }
步骤 8:创建一个局部变量 expenses 来保存来自服务器的支出。
export class ListExpensesComponent implements OnInit{ expenses: Expense[] = []; constructor(private http: HttpClient) { } ngOnInit(): void { } }
步骤 9:通过传递 url 和选项来调用 this.http(HttpClient 实例)对象的 get 方法,并从服务器获取支出对象。然后,将支出设置到我们的局部变量 expenses 中。
export class ListExpensesComponent implements OnInit{ expenses: Expense[] = []; constructor(private http: HttpClient) { } ngOnInit(): void { this.http.jsonp<Expense[]>('https://127.0.0.1:8000/api/jsonp/expense', 'callback') .subscribe( data => { this.expenses = data as Expense[] console.log(this.expenses) }) } }
这里:
将 Expense[] 设置为服务器返回的对象的类型。服务器将在其主体中以 JSON 格式发送支出对象的数组。
订阅请求 (this.http.jsonp) 对象。然后将订阅的数据解析为支出对象的数组,并将其设置为局部支出变量 (this.expenses)
步骤 10:ListExpensesComponent 的完整代码如下:
import { Component, OnInit } from '@angular/core'; import { HttpClient, HttpRequest, HttpResponse, HttpEvent } from '@angular/common/http'; import Expense from '../Expense'; @Component({ selector: 'app-list-expenses', templateUrl: './list-expenses.component.html', styleUrls: ['./list-expenses.component.css'] }) export class ListExpensesComponent implements OnInit { expenses: Expense[] = []; constructor(private http: HttpClient) { } ngOnInit(): void { this.http.jsonp<Expense[]>('https://127.0.0.1:8000/api/jsonp/expense', 'callback') .subscribe( data => { this.expenses = data as Expense[] console.log(this.expenses) }) } }
步骤 11:接下来,从组件获取 expenses 对象并在我们的组件模板页面 (list-expenses.component.html) 中呈现它
<div><h3>Expenses</h3></div> <ul> <li *ngFor="let expense of expenses"> {{expense.item}} @ {{expense.location}} for {{expense.amount}} USD on {{expense.spendOn | date:'shortDate' }} </li> </ul>
步骤 12:最后,使用以下命令运行应用程序:
ng serve
步骤 13:打开浏览器并导航到 https://127.0.0.1:4200/ url 并检查输出
在这里,输出显示我们的支出作为项目列表。
结论
Angular 提供了一种简单的方法来通过 HttpClient 对象请求服务器。jsonp() 是一个特定方法,用于即使服务器不支持跨域 API 调用 (CORS) 也能从服务器获取资源。