我已将ASP.NET核心Web API部署到Azure,我可以使用Swagger或像Fiddler这样的Web调试器访问其端点。在这两种情况下(Swagger中的相同来源,使用来自我的计算机的Fiddler的不同来源),在访问API时,我得到了预期的结果,在我的Startup.cs
中启用了CORS:
将services.AddCors();
添加到ConfigureServices
。
将中间件添加到Configure
:我知道此处的订单很重要(ASP.NET 5: Access-Control-Allow-Origin in response),因此我将此调用放在方法的顶部,只是在记录之前或诊断中间件;这是我的完整方法:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory,
IDatabaseInitializer databaseInitializer)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddNLog();
// to serve up index.html
app.UseDefaultFiles();
app.UseStaticFiles();
// http://www.talkingdotnet.com/aspnet-core-diagnostics-middleware-error-handling/
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
// CORS
// https://docs.asp.net/en/latest/security/cors.html
app.UseCors(builder =>
builder.WithOrigins("http://localhost:4200", "http://www.myclientserver.com")
.AllowAnyHeader()
.AllowAnyMethod());
app.UseOAuthValidation();
app.UseOpenIddict();
app.UseMvc();
databaseInitializer.Seed().GetAwaiter().GetResult();
env.ConfigureNLog("nlog.config");
// swagger
app.UseSwagger();
app.UseSwaggerUi();
}
开发期间使用localhost
CORS,并引用Angular2 CLI应用程序。 CORS在本地工作正常,我的客户端和API应用程序位于同一本地主机上的不同端口上,所以这是“真正的”交叉起源(我正在评论这个,因为我在这里找到的建议:https://weblog.west-wind.com/posts/2016/Sep/26/ASPNET-Core-and-CORS-Gotchas:该帖子的作者注意到响应中的CORS头仅在实际需要时发送 ,即在真正的跨源环境中。)
使用Fiddler我可以成功访问远程API,但我得到NO Access-Control-Allow-Origin
标题。因此,当从浏览器(通过我的客户端应用程序)调用API时,即使服务器返回200,AJAX请求也会失败。示例Fiddler请求(成功):
GET http://mywebapisiteurl/api/values HTTP/1.1
User-Agent: Fiddler
响应:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=3d551180c72208c1d997584c2b6119cf44e3a55c868f05ffc9258d25a58e95b1;Path=/;Domain=prinapi.azurewebsites.net
Date: Thu, 01 Dec 2016 10:30:19 GMT
["value1","value2"]
尝试访问部署在Azure上的远程API时,我的客户端应用程序始终无法通过其AJAX请求失败:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.myclientserver.com' is therefore not allowed access.
以下是使用Angular2的示例客户端代码(使用Plunker):
import {Component, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import { Http, Headers, Response } from '@angular/http';
import { HttpModule } from '@angular/http';
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<button (click)="test()">test</button>
</div>
`,
})
export class App {
name:string;
constructor(private _http: Http) {
this.name = 'Angular2'
}
public test() {
this._http.get('http://theapisiteurlhere/api/values',
{
headers: new Headers({
'Content-Type': 'application/json'
})
})
.subscribe(
(data: any) => {
console.log(data);
},
error => {
console.log(error);
});
}
}
@NgModule({
imports: [ BrowserModule, HttpModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
总而言之,似乎ASPNET API服务器没有返回预期的CORS头,因此我在不同源上托管的基于浏览器的客户端失败。然而,CORS设置似乎没问题,至少从上面引用的文档判断;我处在真正的跨性别环境中;我把中间件放在其他人之前。也许我错过了一些明显的东西,但谷歌搜索这些是我发现的所有建议。任何提示?
更新
回复@Daniel J.G:来自提琴手的请求/回复是成功的:
GET http://theapiserver/api/values HTTP/1.1
User-Agent: Fiddler
Host: theapiserver
Origin: http://theappserver/apps/prin
和
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: http://theappserver/apps/prin
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=3d551180c72208c1d997584c2b6119cf44e3a55c868f05ffc9258d25a58e95b1;Path=/;Domain=theapiserver
Date: Thu, 01 Dec 2016 14:15:21 GMT
Content-Length: 19
["value1","value2"]
据报道,Angular2(Plunker)的请求/响应失败了。通过检查网络流量,我只能看到预检请求:
OPTIONS http://theapiserver/api/values HTTP/1.1
Host: theapiserver
Proxy-Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://run.plnkr.co
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Referer: http://run.plnkr.co/h17wYofXGFuTy2Oh/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,it;q=0.6
HTTP/1.1 204 No Content
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=3d551180c72208c1d997584c2b6119cf44e3a55c868f05ffc9258d25a58e95b1;Path=/;Domain=theapiserver
Date: Thu, 01 Dec 2016 14:23:02 GMT
此后,请求失败,没有更多流量进入服务器。报告的问题是Response to preflight request doesn't pass access control check
,同样是因为响应中缺少标题:
XMLHttpRequest cannot load http://theapiserver/api/values. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://run.plnkr.co' is therefore not allowed access.
答案 0 :(得分:8)
以下是我自己的问题的答案,从评论中复制:我没有注意到在 Azure门户中有一个CORS部分。如果我没有在那里输入任何允许的来源,我的基于代码的配置似乎完全无关紧要。这对我来说很奇怪,因为我不得不在这里复制网址,但是一旦我将*
添加到允许的来源,就会有效。
答案 1 :(得分:3)
添加.AllowAnyHeader()方法可以解决您的问题
app.UseCors(builder => builder.WithOrigins("http://localhost:4200")
.AllowAnyMethod()
.AllowAnyHeader());
答案 2 :(得分:2)
我遇到了类似的错误,但通过保持管道井然有序,我的错误得到了解决。 (startup.cs -> configureServices) 喜欢
import sys
import copy
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
data = [['a','b','c','x','y'],['d','e','f','x','y'],['g','h','i','x','y']]
class TableModel(QAbstractTableModel):
def __init__(self, data):
super(TableModel, self).__init__()
self._data = data
def data(self, index, role):
if role == Qt.DisplayRole:
# See below for the nested-list data structure.
# .row() indexes into the outer list,
# .column() indexes into the sub-list
return self._data[index.row()][index.column()]
def setData(self, index, value, role=Qt.EditRole):
if role == Qt.EditRole:
row = index.row()
column = index.column()
self._data[row][column] = value
self.dataChanged.emit(index, index)
return True
return QAbstractTableModel.setData(self, index, value, role)
def rowCount(self, index):
# The length of the outer list.
return len(self._data)
def columnCount(self, index):
# The following takes the first sub-list, and returns
# the length (only works if all rows are an equal length)
return len(self._data[0])
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.selection = data[0]
# buil UI
self.init_ui()
def init_ui(self):
# layout
self.box_window = QVBoxLayout()
# content
self.invisible_table = QTableView()
tmp = copy.deepcopy(data)
tmp.insert(0,self.selection)
self.model = TableModel(tmp)
self.invisible_table.setModel(self.model)
self.invisible_table.setSelectionBehavior(QTableWidget.SelectRows)
self.invisible_table.horizontalHeader().hide()
self.invisible_table.horizontalHeader().setMinimumSectionSize(100)
self.invisible_table.verticalHeader().hide()
# self.invisible_table.hide()
for i in range(1,self.model.rowCount(0)):
self.invisible_table.setRowHidden(i,True)
self.invisible_table.doubleClicked.connect(self.clicked)
self.invisible_table.clicked.connect(self.clicked)
self.invisible_table.setMinimumSize(1,1)
self.invisible_table.resizeColumnsToContents()
self.invisible_table.resizeRowsToContents()
# self.box_window.addLayout(self.visible_line)
self.box_window.addWidget(self.invisible_table)
self.box_window.addStretch()
# build central widget and select it
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.centralWidget().setLayout(self.box_window)
# show window
self.setGeometry(50,50,1024,768)
self.setWindowTitle("Test")
self.show()
def popup(self, widget):
print("popup")
print(widget)
self.invisible_table.show()
def clicked(self, qmi):
print("clicked")
rowIndex = qmi.row()
if rowIndex == 0:
for i in range(1,self.model.rowCount(0)):
if self.invisible_table.isRowHidden(i):
self.invisible_table.setRowHidden(i,False)
else:
self.invisible_table.setRowHidden(i,True)
else:
self.selection = data[rowIndex-1]
print(self.selection)
col = 0
for d in self.selection:
# self.model._data[0][col]=d
self.model.setData(self.model.index(0,col),d)
col += 1
for i in range(1,self.model.rowCount(0)):
self.invisible_table.setRowHidden(i,True)
def main():
app = QApplication(sys.argv)
main_window = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
答案 3 :(得分:0)
该错误消息非常容易引起误解。尝试将新表添加到DbContext后,出现了相同的错误。 Angular没有给出“ Access-Control-Allow-Origin”错误,但Postman却给出了500 Internal Server错误。尝试调用_userManager.FindByEmailAsync()时,登录方法失败。希望这对其他人有帮助。
答案 4 :(得分:-1)
WebApi项目---&gt;右键单击References ---&gt;在Manage Nuget Packages部分中搜索Core。通过安装
将Microsoft.AspNet.WebApi.Cors添加到项目中将以下代码添加到项目中App_Start文件夹下的WebApi.Config文件中。
var cors = new EnableCorsAttribute(“”,“”,“*”); config.EnableCors(CORS);
答案 5 :(得分:-4)
万一你懒得理解场景背后的魔法UseCors
。
// Summary:
// Adds a CORS middleware to your web application pipeline to allow cross domain
// requests.
//
// Parameters:
// app:
// The IApplicationBuilder passed to your Configure method.
//
// configurePolicy:
// A delegate which can use a policy builder to build a policy.
//
// Returns:
// The original app parameter
现在您可以安全地使用以下行
app.UseCors(builder =>
builder.WithOrigins("http://localhost:53593")
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());