You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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头,避免重复配置。

最后验证

  1. 重启Java服务端
  2. 重启Angular应用(ng serve --open)
  3. 再次调用接口,即可正常获取数据

内容的提问来源于stack exchange,提问作者Socrates

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:40:01