Angular 5(Ionic)调用TMDB API时JSONP跨域请求失败求助
我来帮你搞定这个JSONP的问题——你遇到的错误根源是手动在URL里添加了callback=JSONP_CALLBACK,和Angular的HttpClientJsonpModule自动生成的回调函数名冲突了,导致接口返回了一个包含两个回调名的无效响应。
正确的实现步骤:
1. 确认AppModule的导入(你的这部分是对的,再核对下)
确保HttpClientModule和HttpClientJsonpModule都正确导入并添加到imports数组中:
import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http'; // ...其他必要的导入 @NgModule({ declarations: [/* 你的组件 */], imports: [ BrowserModule, IonicModule.forRoot(MyApp), HttpClientModule, HttpClientJsonpModule // 必须添加这个模块才能使用JSONP ], // ...其他配置 }) export class AppModule {}
2. 修改组件中的请求代码
不要手动在URL里添加callback参数,Angular会自动帮你生成并追加正确的回调函数名。只需要传入基础的API URL,然后在jsonp()方法的第二个参数指定接口使用的回调参数名(TMDB的API用的是callback):
import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; // ...其他导入 @Component({ selector: 'page-your-component', templateUrl: 'your-component.html', }) export class YourComponent { films: Observable<any>; constructor( public navCtrl: NavController, public navParams: NavParams, public http: HttpClient ) { // 注意:这里去掉了&callback=JSONP_CALLBACK const apiKey = '[你的API_KEY]'; const url = `https://api.themoviedb.org/3/movie/550?api_key=${apiKey}`; // 第二个参数'callback'告诉Angular,接口的回调参数名是callback this.films = this.http.jsonp(url, 'callback'); } }
3. 模板代码保持不变
你原来的模板代码是正确的,async管道会自动订阅Observable并处理数据:
<ion-content padding> <ion-list> <button ion-item> {{(films | async)?.title}} </button> </ion-list> </ion-content>
为什么之前的代码会报错?
Angular的HttpClient.jsonp()方法会自动完成以下操作:
- 生成一个唯一的回调函数名(比如
ng_jsonp_callback_0) - 在你提供的URL末尾追加
?callback=生成的函数名 - 注册这个回调函数,等待接口响应后自动调用并解析数据
你手动添加了&callback=JSONP_CALLBACK后,URL里会有两个callback参数(或者TMDB的接口把两个值合并成了数组),所以接口返回了["ng_jsonp_callback_0","JSONP_CALLBACK"](...)这样的响应——JavaScript无法把一个数组当作函数来调用,自然就抛出了TypeError: ["ng_jsonp_callback_0","JSONP_CALLBACK"] is not a function的错误。
额外说明
TMDB的API确实支持JSONP,并且回调参数名就是callback,所以我们在jsonp()方法中指定第二个参数为'callback'是完全正确的。这样修改后,Angular会自动处理所有回调相关的逻辑,你就可以正常获取数据啦。
内容的提问来源于stack exchange,提问作者Nicolau Sunyer

