简体   繁体   English

本地主机上的 React Native 和 C# WebAPI 之间的获取命令返回网络请求失败错误

[英]Fetch Command Between React Native and C# WebAPI on Localhost Returns Network Request Failed error

I'm having an issue in React Native in Android and iOS where I'm trying to run a fetch command to point to a C# WebAPI endpoint running on my localhost .我在 Android 和 iOS 中的 React Native 中遇到问题,我试图运行fetch命令以指向在我的localhost上运行的 C# WebAPI 端点。 I keep getting the following error:我不断收到以下错误:

[TypeError: Network request failed]

I notice that if I have the fetch command point to an external source (see comment in the code below) that the fetch works just fine.我注意到,如果我让fetch命令指向外部源(请参阅下面代码中的注释),那么fetch就可以正常工作。 But for a localhost connection, I can't get this thing to work at all.但是对于localhost连接,我根本无法让这个东西工作。

Here's the code for my login page in React Native:这是我在 React Native 中登录页面的代码:

import "react-native-gesture-handler";
import { StatusBar } from "expo-status-bar";
import React, { useState, Component } from "react";
import {
  StyleSheet,
  Text,
  TextInput,
  View,
  Button,
  Dimensions,
  TouchableOpacity,
} from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import NetInfo from "@react-native-community/netinfo";
import { getUniqueId } from "react-native-device-info";
import { API_URL, PRIMARY_COLOR, QUATERNARY_COLOR } from "../env.json";
import * as Linking from "expo-linking";

var width = Dimensions.get("window").width - 20;

const LogInTheUser = (emailAddress, password) => {
  console.log(`${API_URL}/Login`);
  let userInfo = fetch(`https://localhost:44371/api/Login`, {
    //"https://devapi.flouriish.io/api/Login", {
    method: "POST",
    cache: "no-cache",
    mode: "cors",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      emailAddress: emailAddress,
      password: password,
      ipAddress: ipAddress,
      deviceUUID: deviceUUID,
    }),
  })
    .then((response) => response.json())
    .then((responseData) => {
      console.log(responseData);
      return responseData;
    })
    .catch((error) => console.warn(error));
};

const deviceUUID = getUniqueId();
let ipAddress = "127.0.0.1";
NetInfo.fetch().then((state) => {
  ipAddress = state.details.ipAddress;
});

export default class Login extends Component {
  state = {
    emailAddress: "",
    password: "",
  };
  static navigationOptions = {
    title: "ResetPassword",
  };

  render() {
    return (
      <View style={styles.login}>
        <Text style={styles.label}>Email Address</Text>
        <TextInput
          style={styles.input}
          placeholder="Email Address"
          placeholderTextColor={PRIMARY_COLOR}
          onChangeText={(value) => this.setState({ emailAddress: value })}
          value={this.state.emailAddress}
        />
        <Text style={styles.label}>Password</Text>
        <TextInput
          style={styles.input}
          placeholder="Password"
          placeholderTextColor={PRIMARY_COLOR}
          onChangeText={(value) => this.setState({ password: value })}
          value={this.state.password}
          secureTextEntry={true}
        />
        <Text style={styles.label}>IP Address: {ipAddress}</Text>
        <Text style={styles.label}>Device UUID: {deviceUUID}</Text>
        <Button
          title="Login"
          color={PRIMARY_COLOR}
          onPress={() =>
            LogInTheUser(this.state.emailAddress, this.state.password)
          }
        />
        <TouchableOpacity
          style={styles.label}
          onPress={() => this.props.navigation.navigate("ForgotPassword")}
        >
          <Text style={{ color: PRIMARY_COLOR }}>Forgot Password?</Text>
        </TouchableOpacity>

        <StatusBar style="auto" />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  login: {
    flex: 1,
    backgroundColor: QUATERNARY_COLOR,
    alignItems: "center",
  },
  label: {
    marginTop: 10,
    color: PRIMARY_COLOR,
    marginBottom: 10,
  },
  input: {
    height: 40,
    width: width,
    margin: 12,
    borderWidth: 1,
    borderColor: PRIMARY_COLOR,
    color: PRIMARY_COLOR,
  },
});

Here's the AndroidManifest.xml for the React Native app:这是 React Native 应用程序的AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.akmaziofrontend">
  <uses-permission android:name="android.permission.INTERNET"/>
  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
  <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
  <uses-permission android:name="android.permission.VIBRATE"/>
  <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <application android:name=".MainApplication"
               android:label="@string/app_name"
               android:icon="@mipmap/ic_launcher"
               android:roundIcon="@mipmap/ic_launcher_round"
               android:allowBackup="false"
               android:theme="@style/AppTheme"
               android:usesCleartextTraffic="true">
    <meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@akmazio/akmazio-frontend"/>
    <meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="41.0.0"/>
    <meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize"
        android:theme="@style/Theme.App.SplashScreen">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name = "android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme = "flouriish" />
      </intent-filter>
    </activity>
    <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
  </application>
</manifest>

Here's the code for the API endpoint found at https://localhost:44371/api/Login :这是在https://localhost:44371/api/Login找到的 API 端点的代码:

using akmazio_api.Classes;
using akmazio_api.Contexts;
using akmazio_api.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Security;
using System.Text;
using System.Threading.Tasks;

namespace akmazio_api.Services
{
    public class LoginService : BaseService
    {
        public LoginService(IConfiguration configuration, DatabaseContext context)
            : base(configuration, context) { }

        public User Login(Login login)
        {
            var user = Context.Users
                .Include(x => x.UserRole)
                .Include(x => x.UserType)
                .Include(x => x.Business)
                .Include(x => x.Business.Address)
                .Include(x => x.Address)
                .Single(x => x.EmailAddress == login.EmailAddress && x.IsVerified);
            var computedHash = Cryptography.ComputeHash(login.Password, user.Salt);

            if (!user.PasswordHash.Equals(computedHash))
            {
                throw new SecurityException("User login credentials are not valid");
            }
            else
            {
                var userLoginTokens = Context.UserLoginTokens
                    .Include(x => x.User)
                    .Where(x => x.User.UserId == user.UserId &&
                        x.IPAddress == login.IPAddress && x.DeviceUUID == login.DeviceUUID);
                
                if (userLoginTokens.Any())
                {
                    var token = userLoginTokens.First().Token;
                    user.Token = token;
                    return user.GetScrubbedUser();
                }
                else
                {
                    var userLoginToken = new UserLoginToken()
                    {
                        User = user,
                        Token = Guid.NewGuid().ToString(),
                        IPAddress = login.IPAddress,
                        DeviceUUID = login.DeviceUUID
                    };
                    Context.UserLoginTokens.Add(userLoginToken);
                    Context.SaveChanges();
                    user.Token = userLoginToken.Token;
                    return user.GetScrubbedUser();
                }
            }
        }
    }
}

Here's the Startup.cs file that enables CORS:这是启用 CORS 的Startup.cs文件:

using akmazio_api.Contexts;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace akmazio_api
{
    public class Startup
    {
        public Startup(IWebHostEnvironment env)
        {
            var builder = new ConfigurationBuilder();
            if (!env.IsProduction())
            {
                builder
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true)
                    .AddEnvironmentVariables();
            }
            else
            {
                builder
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddEnvironmentVariables();
            }
            Configuration = builder.Build();
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(Configuration);
            services.AddControllers();
            services.AddSwaggerDocument(settings =>
            {
                settings.Version = "v1";
                settings.Title = "Akmazio Flouriish API";
            });
            services.AddCors(o => o.AddPolicy("DevPolicy", builder =>
            {
                builder.AllowAnyOrigin()
                       .AllowAnyMethod()
                       .AllowAnyHeader();
            }));
            services.AddCors(o => o.AddPolicy("ProdPolicy", builder =>
            {
                builder.WithOrigins("https://flouriish.io")
                       .AllowAnyMethod()
                       .AllowAnyHeader();
            }));
            services.AddDbContext<DatabaseContext>(option =>
                option.UseSqlServer(Configuration["ConnectionStrings:DatabaseConnection"]));
            services.AddDatabaseDeveloperPageExceptionFilter();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment() || env.IsEnvironment("Local"))
            {
                app.UseOpenApi();
                app.UseSwaggerUi3();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "akmazio_api v1"));
                app.UseExceptionHandler("/error-local-development");
            }
            else
            {
                app.UseExceptionHandler("/error");
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();
            app.UseAuthentication();

            if (env.IsDevelopment() || env.IsEnvironment("Local"))
            {
                app.UseCors("DevPolicy");
            }
            else if (env.IsProduction())
            {
                app.UseCors("ProdPolicy");
            }

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

            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
            });
        }
    }
}

Does anybody here have any idea how to fix this issue?这里有人知道如何解决这个问题吗? As you've seen I've tried setting up CORS fixes as well as adding cleartext traffic, but no juice.如您所见,我尝试设置 CORS 修复以及添加明文流量,但没有任何效果。 Any suggestion is appreciated.任何建议表示赞赏。

May be you need to add CORS policy attribute on top of LoginService also.可能您还需要在 LoginService 之上添加 CORS 策略属性。

[EnableCors("<YOUR_CORS_POLICY_NAME_GOES_HERE>")]
public class LoginService : BaseService
{ ... }

localhost only work in your windows application than run in your OS if you use emulator or real device for test & debug you most run visual studio iis express web server by ip address如果您使用模拟器或真实设备进行测试和调试,localhost 只能在您的 Windows 应用程序中运行,而不是在您的操作系统中运行

  1. please lunch visual studio Run as Adminstartor请午餐视觉工作室以管理员身份运行
  2. go to your visual studio project folder and find .vs hidden folder where is sln file.转到您的 Visual Studio 项目文件夹并找到 .vs 隐藏文件夹,其中 sln 文件。
  3. find applicationhost.config file and open it by editor找到 applicationhost.config 文件并用编辑器打开它
  4. in sites tag find sub tag site and set bindingInformation *:xxxx:在站点标签中找到子标签站点并设置 bindingInformation *:xxxx:

binding protocol="http" bindingInformation="*:4732:"绑定协议="http" 绑定信息="*:4732:"

for example 4732=>xxxx is my project.例如 4732=>xxxx 是我的项目。

run asp application you can access to iis express web server by any local ip set in Lan,WLan运行 asp 应用程序,您可以通过 LAN、WLan 中设置的任何本地 ip 访问 iis express web 服务器

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C# webapi Cors 服务器中的选项请求返回错误 404 未找到 - C# webapi Cors Option request in server returns error 404 not found React Axios - C#WebAPI请求令牌失败,没有服务器错误 - React Axios - C# WebAPI request token fails without a server error c# 对网页的代理请求返回错误? - c# proxy request to webpage returns error? C# HttpWebRequest 为本地主机返回 503 错误 url - C# HttpWebRequest returns 503 error for localhost url C#调用aspnet webapi令牌终结点在我的本地主机上完美运行,但在服务器上给出错误 - C# calling aspnet webapi token endpoint works perfectly on my localhost but givens error on server C#和SQL Server:获取数据然后删除将返回错误 - C# & SQL Server : fetch data and then delete returns error C#Webapi帮助页面请求模型自定义 - C# Webapi HelpPage Request Model Customization C# Nancy.Hosting.Self 不响应来自网络的请求,只响应本地主机请求 - C# Nancy.Hosting.Self doesn't answer to requests from network, only to localhost request 从React将Json发布到C#WebApi - Posting Json to C# WebApi from React 为什么原生编译失败但没有 C# 错误(NotificationManager 继承) - Why native compilation failed but no C# error (NotificationManager inheritance)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM