Angular CORS 请求被阻止

Posted

技术标签:

【中文标题】Angular CORS 请求被阻止【英文标题】:Angular CORS request blocked 【发布时间】:2018-10-18 15:46:41 【问题描述】:

我正在尝试将我的 Angular 应用程序与 Express 上的简单 REST 服务器连接起来。服务器仅发送json 数据以响应请求。为了添加 CORS 支持,我使用了 npm 的 cors 模块。在 Angular 应用程序上,我按照以下问题的说明添加了 HttpHeaders:Angular CORS request blocked。

这是我设置 cors 选项的 express 代码: `

// async CORS setup delegation
function corsOptsDelegator(req, cb) 
    let opts = ,
        origin = req.header('Origin');
    if(imports.allowedOrigins.indexOf(origin) === 1) opts.origin = true;
    else opts.origin = false;
    opts.optionsSuccessStatus = 200;
    opts.methods = ['POST', 'GET']; // allowed methods
    opts.credentials = true; // for passing/setting cookie 
    opts.allowedHeaders = ['Content-Type', 'Accept', 'Access-Control-Allow-Origin']; // restrict headers 
    opts.exposedHeaders = ['Accept', 'Content-Type']; // for exposing custom headers to clients; use for hash
    cb(null, opts);

`

这是我将它添加到全局 get 处理程序的方法:

`
app.get('/', cors(corsOptsDelegator), (res, req, nxt) => 
    // only for adding cors on all requests
    nxt();
);
`

我是这样设置 Angular 服务的:

`

export class ContentGetterService 

  private root: string;
  private corsHeaders: HttpHeaders;
  //private contents: string;

  constructor(private http: HttpClient) 
    this.root = 'http://localhost:8888';
    this.corsHeaders = new HttpHeaders(
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Access-Control-Allow-Origin': 'http://localhost:4200'
    );
    //this.contents = '';
   

  getContent(subs: Array<string>): Observable<IContent> 
    return (() => 
      return this.http.get<IContent>( (() => 
        let r = this.root;
        subs.forEach((s, i, a) => 
          if(i === a.length-1) 
            r += s;
          
          else 
            if(s !== '/') 
              r += s;
            
          
        );
        return r;
      )(), 
        headers: this.corsHeaders
      );

    )();
  
  

浏览器警告:Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8888/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

谢谢。

【问题讨论】:

【参考方案1】:

如果你使用 angular-cli,你可以使用代理:

proxy.conf.json


  "/api": 
    "target": "http://localhost:8888",
    "secure": false
  

将所有带有 /api 前缀的请求重定向到 localhost:8888 而不会出现任何 cors 问题。

官方文档:https://angular.io/guide/build#proxying-to-a-backend-server

【讨论】:

这是一个可行的解决方案,但我坚持使用 cors。感谢您的努力。 即使我像您上面提到的那样使用代理,我仍然会遇到这个问题。 为我工作。但是对于 Angular 版本 >6,有一个更新的文档。 angular.io/guide/build#proxy-multiple-entries 请注意,这只适用于开发环境,不适用于生产环境【参考方案2】:

允许您从 Angular JS 访问的服务器端,在这种情况下,您需要允许 http://localhost:8888/,因为那是您的服务器端 URL,在 http://localhost:4200 上运行 Angular。请检查 Http。然后就可以了

【讨论】:

我相信这就是你的意思:this.corsHeaders = new HttpHeaders( 'Content-Type': 'application/json', 'Accept': 'application/json', 'Access-Control-Allow-Origin': 'http://localhost:8888' ); 不幸的是,尝试了同样的错误。 如果您使用secure: false,则无需使用cors中间件进行检查,然后将该代码也删除。这意味着从您的角度中删除 cors 功能。我认为那不是一个好主意。 我同意关闭 cors 是个坏主意。 是的,因为我们总是允许来自客户端的服务器端。不是客户端。 请查看此网址以更好地理解github.com/chandan4u/Node-JS-Security-Implementation/blob/…【参考方案3】:

使用此代码并根据您的结构管理自己。

app.use(
    cors( 
        origin: http://localhost:4200, 
        methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
        allowedHeaders: [
            'Content-Type', 
            'Authorization', 
            'Origin', 
            'x-access-token', 
            'XSRF-TOKEN'
        ], 
        preflightContinue: false 
    )
);

app.get('/', (res, req, nxt) => 
    // only for adding cors on all requests
    nxt();
);

在角度方面

constructor(private http: HttpClient) 
  this.root = 'http://localhost:8888';  //remove
  this.corsHeaders = new HttpHeaders(
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Access-Control-Allow-Origin': '/' .  // edit 
  );
  //this.contents = '';
 

并使用&lt;base&gt;index.html

【讨论】:

我根据你的建议修改了。还是一样的错误。而且,我不确定&lt;base&gt; index.html 是什么意思 &lt;base&gt;href改成什么? 【参考方案4】:

首先,客户端上的问题是由于 Firefox 选择处理飞行前 CORS 的行为。而不是使用GET 方法,而是使用OPTIONS 方法。从我的代码中可以明显看出,我没有任何处理程序来处理OPTIONS。经过一番谷歌搜索,我在 github 上看到了这篇文章:Express CORS middleware。使用它并对我的客户端请求标头进行以下修改,我能够正确启动并运行它。代码如下:

CORS 中间件:

function myCors(req, res, nxt) 
    res.header('Access-Control-Allow-Origin', 'http://localhost:4200');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Access-Control-Allow-Origin, Content-Type, Accept, Accept-Language, Origin, User-Agent');
    if(req.method === 'OPTIONS') 
        res.sendStatus(204);
    
    else 
        nxt();
    
`

将其安装到应用实例: app.use(myCors);

在 Angular 客户端服务上:

this.corsHeaders = new HttpHeaders(
  'Content-Type': 'application/json',
);
// ... adding it to the request
getContent(subs: Array<string>): Observable<IContent> 
return (() => 
  return this.http.get<IContent>( (() => 
    let r = this.root;
    subs.forEach((s, i, a) => 
      if(i === a.length-1) 
        r += s;
      
      else 
        if(s !== '/') 
          r += s;
        
      
    );
    return r;
  )(), 
    headers: this.corsHeaders
  );
 
)();

感谢大家的时间和努力。

编辑

感谢@neutrino 指出在请求中添加Access-Control-* 标头没有意义(并且没有效果)。

【讨论】:

使用Access-Control-Allow-Origin作为请求头不正确吗?我相信标头应该只在服务器响应中使用。我认为您可以完全删除请求标头代码,只要服务器返回正确的标头,它应该仍然可以正常工作。 @neutrino 感谢您的指出。现在我明白了,知道这是错的!【参考方案5】:

在开发环境(本地主机)中,您可以轻松完成,而无需遵循任何这些艰难的步骤。如果您使用的是 firefox,您只需下载https://addons.mozilla.org/firefox/addon/cors-everywhere/,我认为也必须有 chrome 的扩展名。下载后将来到firefox菜单栏,然后​​您可以单击它来激活它,这就是您现在可以访问所有api的所有内容,因为它会自动发送带有所有请求的标头。对于生产环境,您必须通过添加访问控制从服务器配置它-allow-origin to * (all)

【讨论】:

是的,Chrome 也有类似的东西:chrome.google.com/webstore/detail/allow-cors-access-control/…【参考方案6】:

如果您正在使用 Angular CLI、NPM、Spring Data JPA 和 Tomcat 9,我终于找到了在应用服务器 (Tomcat) 上运行的前端 webapp (Angular) 和后端 webapp (Spring Data JPA) 之间进行通信的解决方案)。

在开发环境中:

如果您在默认端口 4200 上运行 ng serve,则 Spring DAO 存储库中的注释 @CrossOrigin("localhost:4200") 就可以了。

@CrossOrigin("http://localhost:4200")
public interface ConfigRepository extends JpaRepository<Config, String> 
    

在生产环境中:

如果您的应用程序在生产服务器上运行,您必须修改您的 web.xml 并添加(例如)内置 CORS 过滤器以允许访问其他资源作为源。

<!-- ==================== CORS Filter Definition ====================== -->

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>http://localhost:8080</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.headers</param-name>
        <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Access-Control-Allow-Origin</param-value>
    </init-param>
    <init-param>
        <param-name>cors.exposed.headers</param-name>
        <param-value>Access-Control-Allow-Origin</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

模板与Tomcat 9 CORS Filter 的区别在于将Access-Control-Allow-Origin 添加到cors.allowed.header 并在cors.allowed.origins 中设置实际允许的来源,例如http://localhost:8080.

因此,无需为 HTTP 请求指定显式标头。感谢@Neutrino。

【讨论】:

以上是关于Angular CORS 请求被阻止的主要内容,如果未能解决你的问题,请参考以下文章

从 Angular App 到 Django REST API 的 API 请求 - 被 CORS 阻止

Angular AWS 被 CORS 策略阻止

CORS 在 dockerized Django REST + Angular 项目中被阻止

Angular - 每个请求都被 CORS 阻止

仅在特定条件下被 CORS 策略阻止的 Angular 请求

被 ionic-5 angular 中的 CORS 策略阻止