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 = '';
并使用<base>
index.html
【讨论】:
我根据你的建议修改了。还是一样的错误。而且,我不确定<base>
index.html 是什么意思
把<base>
href
改成什么?
首先,客户端上的问题是由于 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 阻止
CORS 在 dockerized Django REST + Angular 项目中被阻止