У меня есть приложение .NET Core + React, использующее aspnet-prerendering.Я создал приложение, используя dotnet new reactredux .Я опубликовал это в Azure и направил в это приложение с помощью AWS CloudFront.
Приложение работало во всех средах (локально, CI, предварительная установка ...), но когда я развернул его в производство, оно работало в течение нескольких дней, а затем я начал получать множество ошибок An attempt was made to access a socket in a way forbidden by its access permissions
.Это происходит, когда POST установлен на 127.0.0.1:<randomPort>
.Я не делаю это POST в моем коде, и мне сказали, что это связано с тем, как отреагирует реакция.Эти ошибки обычно начинаются через 1-2 дня после развертывания.Поэтому при первом развертывании все выглядит хорошо, но затем, когда появляются ошибки, они продолжаются до тех пор, пока я повторно не разверну или не перезапущу приложение в Azure.
То, что я пробовал:
- Перезапуск приложения на некоторое время устраняет проблему.
- Я слышал, что это вызвано реакциейгорячая перезагрузка, поэтому я обязательно добавил в Azure набор приложений:
ASPNETCORE_ENVIRONMENT=Production
.Это не решило проблему. - Я попытался полностью закомментировать часть горячей перезагрузки файла Startup.cs, чтобы проверить эту гипотезу ... но ошибки все равно возобновились через 2 дня после развертывания этого кода.
Пример списка портов, которые не срабатывают, с успехом (на первый взгляд случайные ...?):
success count_ data
FALSE 3493 http://127.0.0.1:53571
FALSE 1353 http://127.0.0.1:49988
FALSE 535 http://127.0.0.1:55453
FALSE 484 http://127.0.0.1:53144
FALSE 13 http://127.0.0.1:52428
FALSE 7 http://127.0.0.1:49583
TRUE 11247 http://127.0.0.1:56790
TRUE 10960 http://127.0.0.1:55806
TRUE 10920 http://127.0.0.1:55227
TRUE 9300 http://127.0.0.1:55453
TRUE 8472 http://127.0.0.1:51734
TRUE 5602 http://127.0.0.1:53571
TRUE 5429 http://127.0.0.1:56860
Фрагменты кода:
Запуск:
public void ConfigureServices(IServiceCollection services)
{ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
…
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
ReactHotModuleReplacement = true,
// This configuration suppresses the warnings that the server code doesn't match the client code, which happens on reload.
HotModuleReplacementClientOptions = new Dictionary<string, string>()
{
{ "warn", "false" }
}
});
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseStaticFiles();
…
}
Index.cshtml
@using Microsoft.Extensions.Configuration
@inject Microsoft.AspNetCore.Hosting.IHostingEnvironment hostingEnv
@inject IConfiguration Configuration
<script>
window.data = @Html.Raw(Json.Serialize(@Model));
</script>
<div id="col-app"
asp-prerender-module="./wwwroot/cost-of-living-calculator/dist/main-server"
asp-prerender-webpack-config="webpack.config.server.js"
asp-prerender-data="@Model">Loading...</div>
@if (hostingEnv.EnvironmentName == "Production")
{
<script src="/cost-of-living-calculator/dist/main.min.js" asp-append-version="true"></script>
}
else
{
<script src="/cost-of-living-calculator/dist/main.js" asp-append-version="true"></script>
}
Package.json
...
"aspnet-prerendering": "3.0.1",
"aspnet-webpack": "3.0.0",
"aspnet-webpack-react": "3.0.0",
...
ПРИМЕЧАНИЕ. У меня есть загрузочный сервер изагрузочный клиент, а также конфигурацию веб-пакета сервера и конфигурацию веб-пакета клиента.Это связано с различными потребностями в компиляции сервера / клиента.
Boot-server.js
import React from 'react';
import { createServerRenderer } from 'aspnet-prerendering';
import { renderToString } from 'react-dom/server';
import App from './App';
export default createServerRenderer(
params =>
new Promise((resolve, reject) => {
const data = params.data;
const result = renderToString(React.createElement(App, data));
resolve({ html: result });
})
);
Boot-client.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
const element = document.getElementById('col-app');
ReactDOM.render(<App {...window.data} />, element);
// This is required to trigger the hot reloading functionality
if (module.hot) {
module.hot.accept('./App', () => {
const NewApp = require('./App').default;
ReactDOM.render(<NewApp {...window.data} />, element);
});
}
Webpack.config.js
var path = require('path');
var webpack = require('webpack');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development';
module.exports = () => {
return {
devtool: 'inline-source-map',
entry: {
'main': ['babel-polyfill', './ClientApp/boot-client.js', './ClientApp/index.scss'],
},
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
},
output: {
path: path.join(__dirname, './wwwroot/cost-of-living-calculator/dist'),
publicPath: '/cost-of-living-calculator/dist/',
filename: isDevelopment ? "[name].js" : "[name].min.js"
},
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "[name].css",
chunkFilename: "[id].css"
})
],
module: {
rules: [
{
// JavaScript files, which will be transpiled
// based on .babelrc
test: /\.(js|jsx)$/,
exclude: [/node_modules/],
loader: ['babel-loader', 'source-map-loader']
},
{
test: /\.s?css$/,
use: isDevelopment ? [
'style-loader',
'css-loader',
'sass-loader',
] : [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
}
]
},
mode: isDevelopment ? 'development' : 'production'
}
};
Webpack.config.server.js
var path = require('path');
const isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development';
module.exports = () => {
return {
devtool: 'inline-source-map',
entry: {
'main-server': ['babel-polyfill', './ClientApp/boot-server.js']
},
output: {
path: path.join(__dirname, './wwwroot/cost-of-living-calculator/dist'),
publicPath: '/cost-of-living-calculator/dist/',
filename: "[name].js",
// commonjs is required for server-side compilation
libraryTarget: 'commonjs'
},
module: {
rules: [
{
test: /\.js$/,
exclude: [/node_modules/],
loader: ['babel-loader', 'source-map-loader']
}
]
},
target: 'node',
mode: isDevelopment ? 'development' : 'production'
}
};
Мой вопрос: почему это происходит?Как мне это предотвратить?