Angular 6调用REST接口遇Access-Control-Allow-Origin跨域问题求助
解决Angular 6与Java REST服务的CORS跨域调用问题
你遇到的核心问题是浏览器的CORS预检请求(OPTIONS)未被服务端正确处理——直接在地址栏访问URL能成功,是因为这种请求不会触发浏览器的同源策略校验;但Angular发起的AJAX请求会被拦截,尤其是当请求触发了预检逻辑时。
第一步:修正Angular客户端的错误配置
你在请求里添加的Access-Control-Allow-Origin等头完全没必要,这些是服务端返回给浏览器的响应头,客户端发送这些头不仅无效,反而会触发浏览器发送OPTIONS预检请求,加重问题。
修改你的TourService,移除多余的CORS相关配置:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { Tour } from './tour'; import { catchError, tap } from 'rxjs/operators'; // GET请求无需额外Content-Type头(若服务端无强制要求可直接删除httpOptions) const httpOptions = { headers: new HttpHeaders({}) }; @Injectable({ providedIn: 'root' }) export class TourService { private tourUrl = 'http://localhost:8080/mysite-backend/rest/report'; constructor(private http: HttpClient) { } getTour(id: string): Observable<Tour> { const url = `${this.tourUrl}/single/${id}`; console.log("XXX URL GET " + url) return this.http.get<Tour>(url, httpOptions).pipe( tap(_ => this.log(`fetched tour id=${id}`)), catchError(this.handleError<Tour>(`getTour id=${id}`)) ); } private handleError<T> (operation = 'operation', result?: T) { return (error: any): Observable<T> => { console.error(error); this.log(`${operation} failed: ${error.message}`); return of(result as T); }; } private log(message: string) { console.log("Log message: " + message); } }
第二步:修复Java服务端的CORS处理
问题的关键在于:浏览器会先发送OPTIONS预检请求确认跨域权限,但你的服务端仅在GET接口返回CORS头,未处理OPTIONS请求,导致预检失败,后续GET请求被直接拦截。
推荐两种解决方案:
方案1:全局CORS过滤器(更通用)
创建一个全局过滤器,统一处理所有请求的OPTIONS预检和CORS响应头:
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CORSFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; HttpServletRequest httpRequest = (HttpServletRequest) request; // 允许所有源(生产环境建议指定具体域名) httpResponse.setHeader("Access-Control-Allow-Origin", "*"); // 允许的请求方法 httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); // 允许的请求头 httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); // 预检请求缓存时长(秒),避免重复发送OPTIONS httpResponse.setHeader("Access-Control-Max-Age", "3600"); // 处理OPTIONS预检请求,直接返回200 if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) { httpResponse.setStatus(HttpServletResponse.SC_OK); return; } chain.doFilter(request, response); } @Override public void destroy() {} }
然后在web.xml中配置过滤器(匹配你的REST接口路径):
<filter> <filter-name>CORSFilter</filter-name> <filter-class>com.yourpackage.CORSFilter</filter-class> </filter> <filter-mapping> <filter-name>CORSFilter</filter-name> <url-pattern>/rest/*</url-pattern> </filter-mapping>
方案2:在JAX-RS资源中处理OPTIONS请求
若不想用过滤器,可在ReportResource中添加OPTIONS方法专门处理预检:
@OPTIONS @Path("/{path:.*}") // 匹配所有子路径 public Response handleOptions() { return Response.ok() .header("Access-Control-Allow-Origin", "*") .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") .header("Access-Control-Allow-Headers", "Content-Type") .header("Access-Control-Max-Age", "3600") .build(); }
此时可删除GET方法中的CORS头,避免重复配置。
最后验证
- 重启Java服务端
- 重启Angular应用(
ng serve --open) - 再次调用接口,即可正常获取数据
内容的提问来源于stack exchange,提问作者Socrates
相关产品推荐
相关产品推荐

