如何通过国家名称而非iso2Code调用世界银行API展示国家信息
问题描述
我开发了一个Angular应用,通过服务调用世界银行API获取国家信息,展示搜索到的国家的名称、首都、地区、收入水平、经度和纬度。目前输入两位iso2Code可以成功展示这6项属性,但无法通过国家名称搜索,且世界银行API似乎不支持按国家名称直接查询。
我曾尝试将API返回的数据存入数组,再对比用户输入与数组中的属性值,但不确定如何选择并存储完整对象以展示所需属性,也不确定该方案是否正确。
现有代码
worldbank.service.ts
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class WorldbankService { private apiUrl = 'http://api.worldbank.org/v2/country'; constructor(private http: HttpClient) { } getCountryProperties(countryName: string): Observable<any> { const url = `${this.apiUrl}/${countryName}?format=json`; return this.http.get(url); } }
country-info.component.ts
import { Component } from '@angular/core'; import { WorldbankService } from '../worldbank.service'; @Component({ selector: 'app-country-info', templateUrl: './country-info.component.html', styleUrls: ['./country-info.component.css'] }) export class CountryInfoComponent { countryName = ""; countryProperties: any = null; constructor(private worldbankService: WorldbankService) {} getCountryProperties() { this.worldbankService.getCountryProperties(this.countryName).subscribe( (data: any) => { this.countryProperties = data[1][0]; } ); } }
country-info.component.html
<div class="right-column"> <input type="text" [(ngModel)]="countryName" placeholder="Enter a country name" /> <button (click)="getCountryProperties()">Enter</button> <ul class="properties-list" *ngIf="countryProperties"> <li>Name: {{ countryProperties.name }}</li> <li>Capital: {{ countryProperties.capitalCity }}</li> <li>Region: {{ countryProperties.region.value }}</li> <li>Income Level: {{ countryProperties.incomeLevel.value }}</li> <li>Latitude: {{ countryProperties.latitude }}</li> <li>Longitude: {{ countryProperties.longitude }}</li> </ul> </div>
解决方案
世界银行API确实不支持直接通过国家名称精确/模糊查询,可行方案是先获取所有国家的完整列表并缓存,再在前端根据用户输入的名称做匹配。这样既减少重复API请求,又能实现名称搜索功能。
1. 修改WorldbankService,添加缓存与搜索逻辑
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { map, tap } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class WorldbankService { private apiUrl = 'http://api.worldbank.org/v2/country'; private allCountriesCache: any[] | null = null; // 缓存所有国家数据 constructor(private http: HttpClient) { } // 获取所有国家列表(带缓存,避免重复请求) getAllCountries(): Observable<any[]> { if (this.allCountriesCache) { return of(this.allCountriesCache); } // 加per_page=300确保获取全部国家(API默认只返回50条) const url = `${this.apiUrl}?format=json&per_page=300`; return this.http.get<any>(url).pipe( map(data => data[1]), // 提取国家数据数组 tap(countries => this.allCountriesCache = countries) // 缓存数据 ); } // 根据名称模糊搜索国家 searchCountryByName(name: string): Observable<any[]> { return this.getAllCountries().pipe( map(countries => { const lowerCaseInput = name.toLowerCase().trim(); return countries.filter(country => country.name.toLowerCase().includes(lowerCaseInput) || (country.capitalCity && country.capitalCity.toLowerCase().includes(lowerCaseInput)) // 可选:支持按首都搜索 ); }) ); } // 保留原有的按iso2Code查询方法 getCountryByCode(code: string): Observable<any> { const url = `${this.apiUrl}/${code}?format=json`; return this.http.get<any>(url).pipe( map(data => data[1][0]) ); } }
2. 修改CountryInfoComponent,适配双模式搜索
import { Component } from '@angular/core'; import { WorldbankService } from '../worldbank.service'; @Component({ selector: 'app-country-info', templateUrl: './country-info.component.html', styleUrls: ['./country-info.component.css'] }) export class CountryInfoComponent { inputValue = ""; countryProperties: any = null; searchResults: any[] = []; // 存储搜索结果列表 constructor(private worldbankService: WorldbankService) {} searchCountry() { const input = this.inputValue.trim(); if (!input) { this.countryProperties = null; this.searchResults = []; return; } // 判断输入是否是两位iso2Code(大写字母) if (/^[A-Z]{2}$/.test(input.toUpperCase())) { this.worldbankService.getCountryByCode(input.toUpperCase()).subscribe( country => { this.countryProperties = country; this.searchResults = []; }, () => { this.countryProperties = null; this.searchResults = []; alert('未找到对应国家'); } ); } else { // 按名称搜索 this.worldbankService.searchCountryByName(input).subscribe( results => { this.searchResults = results; this.countryProperties = null; // 如果只有一个匹配结果,自动展示详情 if (results.length === 1) { this.countryProperties = results[0]; this.searchResults = []; } } ); } } // 从搜索结果中选择单个国家 selectCountry(country: any) { this.countryProperties = country; this.searchResults = []; this.inputValue = country.name; } }
3. 修改模板,支持展示搜索结果列表
<div class="right-column"> <input type="text" [(ngModel)]="inputValue" placeholder="输入国家名称或两位代码" /> <button (click)="searchCountry()">搜索</button> <!-- 搜索结果列表 --> <ul class="search-results" *ngIf="searchResults.length > 0"> <li *ngFor="let country of searchResults" (click)="selectCountry(country)"> {{ country.name }} ({{ country.iso2Code }}) </li> </ul> <!-- 国家详情 --> <ul class="properties-list" *ngIf="countryProperties"> <li>名称: {{ countryProperties.name }}</li> <li>首都: {{ countryProperties.capitalCity || '无' }}</li> <li>地区: {{ countryProperties.region.value }}</li> <li>收入水平: {{ countryProperties.incomeLevel.value }}</li> <li>纬度: {{ countryProperties.latitude }}</li> <li>经度: {{ countryProperties.longitude }}</li> </ul> </div>
核心要点
- 缓存机制:第一次获取所有国家数据后会缓存,后续搜索直接用本地数据,减少API请求次数。
- 双模式搜索:自动识别输入是两位代码还是名称,分别走不同的查询逻辑。
- 模糊匹配:搜索时忽略大小写,支持匹配国家名称,还可扩展匹配首都等字段。
- 结果交互:多结果时展示列表,点击列表项可查看详情;单结果时自动展示详情。
内容的提问来源于stack exchange,提问作者Dude Code
相关产品推荐
相关产品推荐

