调用我的 API 时在我的反应应用程序上出现此 CORS 错误 - 请求的资源上不存在“Access-Control-Allow-Origin”标头

Posted

技术标签:

【中文标题】调用我的 API 时在我的反应应用程序上出现此 CORS 错误 - 请求的资源上不存在“Access-Control-Allow-Origin”标头【英文标题】:Getting this CORS error on my react app when calling my API - No 'Access-Control-Allow-Origin' header is present on the requested resource 【发布时间】:2021-04-12 09:11:21 【问题描述】:

我是 React 新手 - 我正在尝试设置我的登录系统以链接到我的 api。我正在尝试从我的 React Redux 应用程序调用我的 .NET 核心 (3.1) API。我的 react 应用在 http://localhost:3000 上,我的 api 在 https://localhost:44383/ 上(不确定这是否重要)。

我在进行 POST 时遇到以下 cors 错误。

我认为问题不在于 api,因为我在 startup.cs ConfigureServices 方法中设置了跨源请求策略(C#)

            services.AddCors(options =>
            
                options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader());

                options.AddPolicy(name: "react",
                  builder =>
                  
                      builder.WithOrigins("http://localhost:3000/").WithHeaders(HeaderNames.AccessControlAllowOrigin, "http://localhost:3000"); ;
                  );
            );

并在配置方法中使用该策略

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseCors("react");

            app.UseAuthentication();

            app.UseAuthorization();

            app.UseAuth();

            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllers();
            );

        

我可以从邮递员的请求中看到附加了正确的标头:

我对 react 不太熟悉 - 但这些是我的身份验证部分,其中包含对带有标头的 api 的调用:

AuthSaga.ts 的 loginEffect() 函数(React/Typescript)

export function* loginEffect(action: any) 
  console.log("loginEffect", action)

  try 
    const data = 
      headers: 
        "content-type": "application/json",
        "Access-Control-Allow-Origin": "http://localhost:3000/"
      ,
      body: 
        ...action.payload,
      ,
    

    const  timeoutDelay, response  = yield race(
      timeoutDelay: delay(10000),
      response: call(AuthAPI.postLogin, data),
    )

    if (timeoutDelay) 
      yield put(setAuthFailure("Server timed out"))
    

    if (response) 
      if (response.status === 200) 
        console.log("200");
        const responseJson = yield response.json()
        yield put(loginSuccess(responseJson))
       else 
        console.log("fail");
        const responseJson = yield response.json()
        yield put(setAuthFailure(responseJson))
      
    
   catch (error) 
    yield put(setAuthFailure("Something went wrong. Try again later."))
  

login.tsx

export const Login: React.FC = (props) => 
  const [username, setUsername] = useState("")
  const [password, setPassword] = useState("")
  const dispatch = useDispatch()

  const handleSubmit = () => 
    dispatch(login( UserName: username, Password: password ))
  

  return (
    <PageWrapper>
      <LoginWrapper>
        <input
          placeholder="Username"
          onChange=(e) => setUsername(e.target.value)
        ></input>
        <input
          placeholder="Password"
          onChange=(e) => setPassword(e.target.value)
        ></input>
      </LoginWrapper>
      <button onClick=handleSubmit>Submit</button>
    </PageWrapper>
  )

AuthAPI.ts

export const AuthAPI: AuthAPIInterface = 
    async postLogin(data: any): Promise<object> 
        const postLoginUrl: string = `$ baseApi.authUrl /login`
        console.log('[URL FOR postLogin]', postLoginUrl);
        console.log(data);


        return fetch(postLoginUrl, 
            method: 'POST',
            headers: data.headers,
            credentials: 'include',
            body: JSON.stringify(data.body)
        )
    ,
    async postRegister(data: any): Promise<object> 
        const postRegisterUrl: string = `$ baseApi.authUrl /register`
        console.log('[URL FOR postRegister]', postRegisterUrl);

        return fetch(postRegisterUrl, 
            method: 'POST',
            headers: data.headers,
            credentials: 'include',
            body: JSON.stringify(data.body)
        )
    

【问题讨论】:

我认为您不需要在标题中使用“Access-Control-Allow-Origin”:“localhost:3000”。由于任何黑客都可以添加它,它没有任何意义。 当 react 应用最终托管在与应用相同的 url 上时,您可以在开发期间使用 proxy。 【参考方案1】:

你有一个错误:

builder.WithOrigins("http://localhost:3000/").WithHeaders(HeaderNames.AccessControlAllowOrigin, "http://localhost:3000"); 

从原点中删除最后一个“/”:

builder.WithOrigins("http://localhost:3000")

并尝试使用所有标题和方法:

options.AddPolicy(name: "react",
                  builder =>
                  
                      builder.WithOrigins("http://localhost:3000")
                   .AllowAnyMethod()
                   .AllowAnyHeader());
                  );

由于您有两个策略,因此您必须将 cors 策略的名称添加到您的控制器操作中,但我认为首先从您的启动中删除或注释“AllowAll”策略。

【讨论】:

以上是关于调用我的 API 时在我的反应应用程序上出现此 CORS 错误 - 请求的资源上不存在“Access-Control-Allow-Origin”标头的主要内容,如果未能解决你的问题,请参考以下文章

使用反应延迟加载时在 Edge 上出现 SCRIPT1028 错误

对managedVM上的localhost节点服务器进行应用程序调用

当反应原生应用程序启动时,将初始状态从 API 调用传递给 createStore

反应本机推送通知在 Android 8.1(API 级别 27)中不起作用

多次在 API 调用上以反应原生方式呈现屏幕

为啥在我第一次单击按钮时在我的 RecyclerView 中调用绑定?