尝试在C#(Blazor WASM)中创建FirebaseDb对象后,将其部署到Firebase后会抛出“阻止的混合内容”错误。 有没有办法强迫它使用HTTPS?
错误:
阻止加载混合的活动内容“ http://169.254.169.254/”
dotnet.3.2.0-preview3.20168.1.js:1:163131
爆击:Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer [100] blazor.webassembly.js:1:36074
未处理的异常呈现组件:TypeError:尝试获取资源时出现NetworkError。 blazor.webassembly.js:1:36074
WebAssembly.JSException:尝试获取资源时发生TypeError:NetworkError。 blazor.webassembly.js:1:36074
在WebAssembly.Net.Http.HttpClient.WasmHttpMessageHandler.doFetch(System.Threading.Tasks.TaskCompletionSource 1[TResult] tcs, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x257c7e0 + 0x00988> in <filename unknown>:0 blazor.webassembly.js:1:36074
at WebAssembly.Net.Http.HttpClient.WasmHttpMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x255e648 + 0x00184> in <filename unknown>:0 blazor.webassembly.js:1:36074
at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task
1 [TResult] sendTask,System.Net.Http.HttpRequestMessage请求,System.Threading.CancellationTokenSource cts,System.Boolean disposeCts)<0x256c970 + 0x00278>在:0 blazor.webassembly.js:1:36074
在Google.Apis.Auth.OAuth2.ComputeCredential.IsRunningOnComputeEngineNoCache()<0x24f5570 + 0x0018c>在:0 blazor.webassembly.js:1:36074
在Google.Apis.Auth.OAuth2.DefaultCredentialProvider.CreateDefaultCredentialAsync()<0x24e22f0 + 0x0020e>中的:0 blazor.webassembly.js:1:36074
在:0 blazor.webassembly.js:1:36074中的Google.Api.Gax.Grpc.ChannelPool.CreateChannelCredentialsUncached()<0x24cf210 + 0x000d8>
在Google.Api.Gax.Grpc.ChannelPool.GetChannelAsync(Google.Api.Gax.Grpc.ServiceEndpoint端点,System.Collections.Generic.IEnumerable`1 [T] channelOptions)<0x246fb30 + 0x000f4>在:0 blazor.webassembly中。 js:1:36074
在Google.Cloud.Firestore.V1.FirestoreClient.CreateAsync(Google.Api.Gax.Grpc.ServiceEndpoint端点,Google.Cloud.Firestore.V1.FirestoreSettings设置)<0x246e908 + 0x000ec>在:0 blazor.webassembly.js:1中:36074
在Google.Cloud.Firestore.FirestoreDb.CreateAsync(System.String projectId,Google.Cloud.Firestore.V1.FirestoreClient客户端)<0x2449d00 + 0x001d0>在:0 blazor.webassembly.js:1:36074
在blog.Pages.Index.OnInitializedAsync()<0x2434eb8 + 0x000c8>中:0 blazor.webassembly.js:1:36074
在:0 blazor.webassembly.js:1:36074中的Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()<0x2330b40 + 0x0014c>中
在Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(System.Threading.Tasks.Task taskToHandle)中的<0x247d5b8 + 0x000c2>在:0 blazor.webassembly.js:1:36074
代码:
protected override async Task OnInitializedAsync()
{
string projectId = "my-poject-id";
FirestoreDb db = await FirestoreDb.CreateAsync(projectId);
}
答案 0 :(得分:1)
目前,您需要使用 JS-Interop:https://docs.microsoft.com/en-us/aspnet/core/blazor/call-javascript-from-dotnet
附言正如@swimburger 很好地指出的那样,服务器端 C# 不起作用;如果为 firebase 添加新的客户端 C# 库,这可能会改变。
答案 1 :(得分:0)
TL; DR
Firestore库不应在浏览器上下文中运行。它被开发用于服务器端或可能在管理工具中使用。该库将允许您在Firestore中进行所有操作,并将凭据传送给客户会带来安全风险。
根据您的堆栈跟踪信息,我假设您正在使用Google.Cloud.Firestore
库。
不幸的是,该库被设计为“ server client library”。服务器端要使用的客户端库。
这些“服务器客户端库”的设计与“ mobile/web client libraries”不同。
移动/网络库将使用Firebase的身份验证(用户名/密码,Facebook等),并且安全模型将应用于该用户上下文。
服务器库实质上使您可以访问所有内容。
现在,您遇到的问题是Blazor不支持该SDK的原因。
首先,SDK依赖的GOOGLE_APPLICATION_CREDENTIALS
环境变量在Blazor应用程序中不可用。
如果可用,则无法从浏览器沙箱中访问该文件。
您可以使用FirestoreDbBuilder
并手动设置JsonCredentials
和ProjectId
来规避这两个问题:
var builder = new FirestoreDbBuilder();
builder.JsonCredentials = "{\"type\": \"service_account\", \"project_id\": \"\", \"private_key_id\": \"\", \"private_key\": \"\", \"client_email\": \"\", \"client_id\": \"\", \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\", \"token_uri\": \"https://oauth2.googleapis.com/token\", \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\", \"client_x509_cert_url\": \"\" }";
builder.ProjectId = "";
FirestoreDb db = builder.Build();
这将导致下一个问题,所使用的GRPC库不支持Blazor / .NET WASM,从而导致此堆栈跟踪:
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Unsupported platform.
System.InvalidOperationException: Unsupported platform.
at Grpc.Core.Internal.NativeExtension.GetNativeLibraryFilename () [0x0003f] in T:\src\github\grpc\src\csharp\Grpc.Core\Internal\NativeExtension.cs:231
at Grpc.Core.Internal.NativeExtension.LoadUnmanagedLibrary () [0x0000a] in T:\src\github\grpc\src\csharp\Grpc.Core\Internal\NativeExtension.cs:93
at Grpc.Core.Internal.NativeExtension.LoadNativeMethods () [0x0001a] in T:\src\github\grpc\src\csharp\Grpc.Core\Internal\NativeExtension.cs:120
at Grpc.Core.Internal.NativeExtension..ctor () [0x00006] in T:\src\github\grpc\src\csharp\Grpc.Core\Internal\NativeExtension.cs:40
at Grpc.Core.Internal.NativeExtension.Get () [0x00022] in T:\src\github\grpc\src\csharp\Grpc.Core\Internal\NativeExtension.cs:65
at Grpc.Core.Internal.NativeMethods.Get () [0x00000] in T:\src\github\grpc\src\csharp\Grpc.Core\Internal\NativeMethods.cs:49
at Grpc.Core.GrpcEnvironment.GrpcNativeInit () [0x00016] in T:\src\github\grpc\src\csharp\Grpc.Core\GrpcEnvironment.cs:373
at Grpc.Core.GrpcEnvironment..ctor () [0x0001e] in T:\src\github\grpc\src\csharp\Grpc.Core\GrpcEnvironment.cs:302
at Grpc.Core.GrpcEnvironment.AddRef () [0x00028] in T:\src\github\grpc\src\csharp\Grpc.Core\GrpcEnvironment.cs:78
at Grpc.Core.Channel..ctor (System.String target, Grpc.Core.ChannelCredentials credentials, System.Collections.Generic.IEnumerable`1[T] options) [0x00041] in T:\src\github\grpc\src\csharp\Grpc.Core\Channel.cs:70
at Google.Api.Gax.Grpc.GrpcCore.GrpcCoreAdapter.CreateChannelImpl (System.String endpoint, Grpc.Core.ChannelCredentials credentials, Google.Api.Gax.Grpc.GrpcChannelOptions options) [0x00000] in T:\src\github\gax-dotnet\releasebuild\Google.Api.Gax.Grpc.GrpcCore\GrpcCoreAdapter.cs:34
at Google.Api.Gax.Grpc.GrpcAdapter.CreateChannel (System.String endpoint, Grpc.Core.ChannelCredentials credentials, Google.Api.Gax.Grpc.GrpcChannelOptions options) [0x00024] in T:\src\github\gax-dotnet\releasebuild\Google.Api.Gax.Grpc\GrpcAdapter.cs:29
at Google.Api.Gax.Grpc.ClientBuilderBase`1[TClient].CreateChannel (System.String endpoint, Grpc.Core.ChannelCredentials credentials) [0x00000] in T:\src\github\gax-dotnet\releasebuild\Google.Api.Gax.Grpc\ClientBuilderBase.cs:423
at Google.Api.Gax.Grpc.ClientBuilderBase`1[TClient].CreateCallInvokerAsync (System.Threading.CancellationToken cancellationToken) [0x00145] in T:\src\github\gax-dotnet\releasebuild\Google.Api.Gax.Grpc\ClientBuilderBase.cs:313
at Google.Cloud.Firestore.V1.FirestoreClientBuilder.BuildAsyncImpl (System.Threading.CancellationToken cancellationToken) [0x00033] in /_/apis/Google.Cloud.Firestore.V1/Google.Cloud.Firestore.V1/FirestoreClient.g.cs:285
at Google.Cloud.Firestore.FirestoreDbBuilder.BuildAsync (System.Threading.CancellationToken cancellationToken) [0x0015a] in /_/apis/Google.Cloud.Firestore/Google.Cloud.Firestore/FirestoreDbBuilder.cs:119
at BlazorFirestore.Pages.FetchData.OnInitializedAsync () [0x00061] in C:\Users\niels\source\repos\BlazorFirestore\Pages\FetchData.razor:12
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync () <0x2ff3be8 + 0x0013a> in <filename unknown>:0
这可以通过使用Grpc.Net.Client.Web
来解决,using System;
using Grpc.Core;
using Google.Api.Gax.Grpc;
using Grpc.Net.Client;
using System.Net.Http;
using Grpc.Net.Client.Web;
// you'll need these packages
// Google.Apis.Auth, Google.Cloud.Firestore, Grpc.Net.Client, Grpc.Net.Client.Web
namespace BlazorFirestore
{
// most of the code was borrowed from https://github.com/googleapis/gax-dotnet/blob/master/Google.Api.Gax.Grpc.GrpcNetClient/GrpcNetClientAdapter.cs
public sealed class GrpcWebAdapter : GrpcAdapter
{
// this HttpClient using the GrpcWebHandler and mode is crucial to get Grpc to work for Firestore
private static HttpClient httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));
// Note: this is "Default" rather than "Instance" as we expect to have other factory methods later, e.g. accepting
// an HTTP client factory.
/// <summary>
/// Returns the default instance of this class.
/// </summary>
public static GrpcWebAdapter Default { get; } = new GrpcWebAdapter();
private GrpcWebAdapter()
{
}
/// <inheritdoc />
protected override ChannelBase CreateChannelImpl(string endpoint, ChannelCredentials credentials, Google.Api.Gax.Grpc.GrpcChannelOptions options)
{
var grpcNetClientOptions = ConvertOptions(credentials, options);
var address = ConvertEndpoint(endpoint);
return GrpcChannel.ForAddress(address, grpcNetClientOptions);
}
// Internal for testing
internal static global::Grpc.Net.Client.GrpcChannelOptions ConvertOptions(ChannelCredentials credentials, Google.Api.Gax.Grpc.GrpcChannelOptions options)
{
// If service config resolution is explicitly enabled, throw - we can't support that,
// and users may be depending on it.
if (options.EnableServiceConfigResolution == true)
{
throw new ArgumentException($"{nameof(options.EnableServiceConfigResolution)} is not currently supported in {nameof(GrpcWebAdapter)}");
}
if (options.CustomOptions.Count > 0)
{
throw new ArgumentException($"Custom options are not currently supported in {nameof(GrpcWebAdapter)}");
}
// Options we ignore:
// - PrimaryUserAgent
// - KeepAliveTime
return new global::Grpc.Net.Client.GrpcChannelOptions
{
Credentials = credentials,
MaxReceiveMessageSize = options.MaxReceiveMessageSize,
MaxSendMessageSize = options.MaxSendMessageSize,
// pass the GrpcWeb version of the httpclient
HttpClient = httpClient
};
}
// Internal for testing
internal static string ConvertEndpoint(string endpoint) =>
// Note that we assume HTTPS for any bare address; this feels like a reasonable assumption for now.
endpoint.StartsWith("http:", StringComparison.Ordinal) || endpoint.StartsWith("https:", StringComparison.Ordinal)
? endpoint : $"https://{endpoint}";
}
}
是Blazor内部可运行的.NET的Grpc实现。
创建以下类(受Google's Source启发):
GrpcWebAdapter.Default
现在将FirestoreDbBuilder.GrpcAdapter
设置为var builder = new FirestoreDbBuilder();
builder.JsonCredentials = "{\"type\": \"service_account\", \"project_id\": \"\", \"private_key_id\": \"\", \"private_key\": \"\", \"client_email\": \"\", \"client_id\": \"\", \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\", \"token_uri\": \"https://oauth2.googleapis.com/token\", \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\", \"client_x509_cert_url\": \"\" }";
builder.ProjectId = "";
builder.GrpcAdapter = GrpcWebAdapter.Default;
FirestoreDb db = builder.Build();
DocumentReference docRef = db.Collection("users").Document("alovelace");
Dictionary<string, object> user = new Dictionary<string, object>
{
{ "First", "Ada" },
{ "Last", "Lovelace" },
{ "Born", 1815 }
};
await docRef.SetAsync(user);
:
Access to fetch at 'https://firestore.googleapis.com/google.firestore.v1.Firestore/Commit' from origin 'https://localhost:5001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
dotnet.3.2.0.js:1 POST https://firestore.googleapis.com/google.firestore.v1.Firestore/Commit net::ERR_FAILED
blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Status(StatusCode="Internal", Detail="Error starting gRPC call. JSException: TypeError: Failed to fetch", DebugException="WebAssembly.JSException: TypeError: Failed to fetch
at System.Net.Http.WebAssemblyHttpHandler.doFetch (System.Threading.Tasks.TaskCompletionSource`1[TResult] tcs, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x3c61b60 + 0x00a30> in <filename unknown>:0
at System.Net.Http.WebAssemblyHttpHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x3c24040 + 0x00174> in <filename unknown>:0
at Grpc.Net.Client.Web.GrpcWebHandler.SendAsyncCore (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x00092] in /_/src/Grpc.Net.Client.Web/GrpcWebHandler.cs:137
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) <0x3d9ae50 + 0x00134> in <filename unknown>:0
at Grpc.Net.Client.Internal.GrpcCall`2[TRequest,TResponse].RunCall (System.Net.Http.HttpRequestMessage request, System.Nullable`1[T] timeout) [0x0020c] in /_/src/Grpc.Net.Client/Internal/GrpcCall.cs:477 ")
Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Error starting gRPC call. JSException: TypeError: Failed to fetch", DebugException="WebAssembly.JSException: TypeError: Failed to fetch
at System.Net.Http.WebAssemblyHttpHandler.doFetch (System.Threading.Tasks.TaskCompletionSource`1[TResult] tcs, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x3c61b60 + 0x00a30> in <filename unknown>:0
at System.Net.Http.WebAssemblyHttpHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x3c24040 + 0x00174> in <filename unknown>:0
at Grpc.Net.Client.Web.GrpcWebHandler.SendAsyncCore (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x00092] in /_/src/Grpc.Net.Client.Web/GrpcWebHandler.cs:137
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) <0x3d9ae50 + 0x00134> in <filename unknown>:0
at Grpc.Net.Client.Internal.GrpcCall`2[TRequest,TResponse].RunCall (System.Net.Http.HttpRequestMessage request, System.Nullable`1[T] timeout) [0x0020c] in /_/src/Grpc.Net.Client/Internal/GrpcCall.cs:477 ")
at Google.Api.Gax.Grpc.ApiCallRetryExtensions+<>c__DisplayClass0_0`2[TRequest,TResponse].<WithRetry>b__0 (TRequest request, Google.Api.Gax.Grpc.CallSettings callSettings) [0x00051] in T:\src\github\gax-dotnet\releasebuild\Google.Api.Gax.Grpc\ApiCallRetryExtensions.cs:27
at Google.Cloud.Firestore.WriteBatch.CommitAsync (Google.Protobuf.ByteString transactionId, System.Threading.CancellationToken cancellationToken) [0x000b5] in /_/apis/Google.Cloud.Firestore/Google.Cloud.Firestore/WriteBatch.cs:231
at Google.Cloud.Firestore.DocumentReference.SetAsync (System.Object documentData, Google.Cloud.Firestore.SetOptions options, System.Threading.CancellationToken cancellationToken) [0x0004b] in /_/apis/Google.Cloud.Firestore/Google.Cloud.Firestore/DocumentReference.cs:181
at BlazorFirestore.Pages.FetchData.OnInitializedAsync () [0x00166] in C:\Users\niels\source\repos\BlazorFirestore\Pages\FetchData.razor:21
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync () <0x2ff3be8 + 0x0013a> in <filename unknown>:0
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask (System.Threading.Tasks.Task taskToHandle) <0x3905a50 + 0x000b6> in <filename unknown>:0
我们距离更近了一步,但是现在我们遇到了CORS安全问题,因为这种与Firestore的通信方式并非旨在通过浏览器运行,并且无法配置与此SDK结合使用的CORS。 这些是导致的错误:
.\chrome.exe --disable-web-security
当您使用Grpc.Net.Client.Web
在浏览器中明确禁用CORS时,结果将是成功的身份验证,但实际的API将返回404。
为什么我会返回404?我可以用Fiddler嗅探 window.addEventListener("load", function () {
//checking is the user is connected to the internet and show content respectively
if (navigator.onLine) {
// NASA API
fetch(
`https://api.nasa.gov/planetary/apod?api_key=MY_KEY`
)
.then((response) => response.json())
.then((data) => {
document.body.style.backgroundImage = `url("${data.url}")`;
})
.catch((err) => console.log("Something's wrong with NASA API"));
}
//when the user is offline
else {
/*THE CODE GOES HERE*/
}
版本,但是默认实现不会被Fiddler拦截。
网络版本似乎使用了不支持的协议/传输或其他某种协议。希望有人可以解决下一个问题。
结论 :. net的Firestore库不应在浏览器沙箱中使用,也不被支持。