Angular 5调用freegeoip获取客户端IP遇跨域问题的解决办法
你的问题核心是浏览器同源策略导致的CORS跨域限制,先给你拆解下原因,再给两个可行的解决方案:
为什么jQuery能正常运行,Angular不行?
jQuery的$.getJSON('//freegeoip.net/json/?callback=?')会自动识别URL里的callback=?,切换成JSONP请求模式——这种模式不是普通的AJAX请求,而是通过动态创建<script>标签加载资源,绕开了浏览器的CORS检查。
而你在Angular里用HttpClient.get()发起的是标准的XHR请求,浏览器会先发送一个OPTIONS预请求验证权限,但freegeoip.net服务器没有配置Access-Control-Allow-Origin响应头,所以预请求失败,就出现了你看到的报错。
解决方案一:改用Angular的JSONP请求
因为freegeoip.net支持JSONP,我们直接用Angular的JSONP模块来实现:
1. 先在AppModule中导入JSONP模块
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http'; import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule, HttpClientModule, HttpClientJsonpModule // 注册JSONP模块 ], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule { }
2. 修改JobService的请求逻辑
把原来的get换成jsonp方法,注意参数里的callback要指定为JSONP_CALLBACK:
import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; @Injectable() export class JobService { constructor( private http: HttpClient) { } getIpAddress(): Observable<any> { // JSONP不需要设置Content-Type头,直接去掉headers return this.http .jsonp('http://freegeoip.net/json/', 'callback') .pipe( catchError(this.handleError) ); } private handleError(error: HttpErrorResponse): Observable<any> { console.error('请求出错: ', error); return throwError(error); } }
3. 组件调用保持不变
你的JobsDetailComponent里的调用逻辑不需要修改,依然是subscribe获取数据即可。
解决方案二:配置Angular代理服务器(本地开发用)
如果你不想用JSONP,也可以通过Angular的代理功能,把本地请求转发到freegeoip.net,这样浏览器只和本地服务器通信,不会触发跨域限制:
1. 在项目根目录创建proxy.conf.json文件
{ "/freegeoip": { "target": "http://freegeoip.net", "secure": false, "pathRewrite": { "^/freegeoip": "" }, "changeOrigin": true } }
2. 修改angular.json中的serve配置
找到architect > serve > options,添加proxyConfig:
"serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "your-project-name:build", "proxyConfig": "proxy.conf.json" }, // ...其他配置 }
3. 修改JobService的请求URL
把原来的URL改成本地代理路径:
getIpAddress(): Observable<any> { return this.http .get('/freegeoip/json/') .pipe( catchError(this.handleError) ); }
这样启动Angular项目时,请求会通过本地代理转发到freegeoip.net,完美绕过CORS限制。
内容的提问来源于stack exchange,提问作者Mohammad Daliri

