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

我正在尝试将我的 Angular 应用程序与 Express 上的简单 REST 服务器连接起来。服务器仅发送json 数据以响应请求。为了添加 CORS 支持,我使用了 npm 的 cors 模块。在 Angular 应用程序上,我按照以下问题的说明添加了 HttpHeadersAngular 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).

谢谢。

【问题讨论】:

    标签: angular express cors


    【解决方案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 是个坏主意。
    • 是的,因为我们总是允许来自客户端的服务器端。不是客户端。
    【解决方案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)

    【讨论】:

    【解决方案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。

    【讨论】:

      猜你喜欢
      • 2022-01-24
      • 2018-09-12
      • 2021-12-26
      • 2020-08-16
      • 2022-11-01
      • 2020-07-18
      • 2022-01-14
      • 2020-08-16
      • 2019-11-30
      相关资源
      最近更新 更多