【问题标题】:Aspnet server rendering debuggingAspnet 服务器渲染调试
【发布时间】:2017-02-18 23:37:56
【问题描述】:

我有一个在 aspnet 核心上运行的 react-redux 应用程序,使用 aspnet 预渲染进行服务器端渲染。

假设我犯了一个编程错误,在子组件中我尝试访问一个未定义的道具,因为一个愚蠢的错字。

import {Child} from './child'
export class Parent extends React.Component {
  render () {
    const someProp = {
      something: "something"
    };
    return <Child someProp={someProp} />;
  }
}

export class Child extends React.Component {
  render() {
    return <div>this.props.someprop.something</div>;
         //typo: should be someProp instead of someprop
}

如果没有服务器渲染,我会遇到类似这样的错误:无法在 x:yy 行访问未定义的内容 但是通过服务器渲染我得到一个:

处理请求时发生未处理的异常。

异常:调用节点模块失败并出现错误:预渲染在 30000 毫秒后超时,因为“ClientApp/src/boot-server”中的引导函数返回了一个未解析或拒绝的承诺。确保你的引导函数总是解决或拒绝它的承诺。您可以使用“asp-prerender-timeout”标签助手更改超时值。

这使得调试变得非常困难,因为您没有得到任何关于哪里出了问题的反馈。 如果出现故障,任何人都知道如何设置拒绝?或者甚至可以调试服务器端呈现的代码?

这是我的启动服务器文件,如果您需要更多文件,请告诉我。

import * as React from 'react';
import { Provider } from 'react-redux';
import { renderToString } from 'react-dom/server';
import configureStore from './store/configureStore';
import {getFormById} from './actions/getFormActions';
import {updateUserLocale} from './actions/userLocaleActions';
import FormResponder from './components/mainComponents/formResponder';

export default function renderApp (params) {

    return new Promise((resolve, reject) => {

        const store = configureStore();
        store.dispatch(getFormById(params.data.id, params.data.config, params.data.authenticationToken));
        store.dispatch(updateUserLocale(params.data.userLocale));
        const app = (
            <Provider store={ store }>
                <FormResponder />
            </Provider>
        );

    // Perform an initial render that will cause any async tasks (e.g., data access) to begin
    renderToString(app);

    // Once the tasks are done, we can perform the final render
    // We also send the redux store state, so the client can continue execution where the server left off
    params.domainTasks.then(() => {
        resolve({
            html: renderToString(app),
            globals: {
                initialReduxState: store.getState(), 
                authenticationToken: params.data.authenticationToken, 
                config: params.data.config
            }
        });
    }, reject); // Also propagate any errors back into the host application
});
}

【问题讨论】:

    标签: asp.net reactjs asp.net-core redux server-rendering


    【解决方案1】:

    我在使用 Visual Studio 2017 时也有过类似的经验。我最终意识到原始错误的诊断信息实际上是在“输出”窗口中。

    【讨论】:

    • 你刚刚救了我发疯!
    【解决方案2】:

    我做了一些研究,得出的结论是暂时无法调试初始服务器呈现的代码。

    我所做的是实现逻辑,以便我可以禁用服务器渲染。

    这就是它的样子:

    public async Task<IActionResult> Index(string id, string userLocale = "en", bool server = true)
    { 
        Guid positionId;
        if (!Guid.TryParse(id, out positionId))
        {
            throw new Exception("Invalid position id");        
        }
    
        var token = await _apiClient.GetToken();
    
        var formData = new ApplicationFormViewModel()
        {
            Id = positionId,
            UserLocale = userLocale,
            AuthenticationToken = token.AccessToken,
            Server = server
        };
        return View(formData);
    }
    

    view.cshtml:

    @{if (@Model.Server) {
        <div 
        class="container"
        id="react-app"
        asp-prerender-module="ClientApp/src/boot-server"
        asp-prerender-data="new {
            Id = @Model.Id, 
            UserLocale = @Model.UserLocale, 
            AuthenticationToken = @Model.AuthenticationToken, 
            Config = new { 
                ApplicationPostUrl = @Url.Action("SaveApplication"),
                AttachmentPostUrl = @Url.Action("UploadAttachment"),
                FormGetUrl = @Url.Action("GetForm")
            }
         }" 
         asp-prerender-webpack-config="webpack.config.js" >
            Loading...
    </div>
    }
    else {
        <script>
            var id= '@Model.Id'; 
            var config= {
                applicationPostUrl: '@Url.Action("SaveApplication")',
                attachmentPostUrl: '@Url.Action("UploadAttachment")',
                formGetUrl: '@Url.Action("GetForm")'
            };
            var userLocale='@Model.UserLocale'; 
            var authenticationToken='@Model.AuthenticationToken'; 
            var server = false;
        </script>
        <div class="container" id="react-app">loading</div>
    
    }
    }
    
    
    
    @section scripts {
    
        <script src="~/dist/main.js" asp-append-version="true"></script>
    }
    

    boot-server.jsx:

    export default function renderApp (params) {
    
        return new Promise((resolve, reject) => {
    
            const store = configureStore();
            store.dispatch(getFormById(params.data.id, params.data.config, params.data.authenticationToken));
            store.dispatch(updateUserLocale(params.data.userLocale));
            const app = (
                <Provider store={ store }>
                    <FormResponder />
                </Provider>
            );
    
        // Perform an initial render that will cause any async tasks (e.g., data access) to begin
        renderToString(app);
    
        // Once the tasks are done, we can perform the final render
        // We also send the redux store state, so the client can continue execution where the server left off
        params.domainTasks.then(() => {
            resolve({
                html: renderToString(app),
                globals: {
                    initialReduxState: store.getState(), 
                    authenticationToken: params.data.authenticationToken, 
                    config: params.data.config,
                    server: true
                }
            });
            }, reject); // Also propagate any errors back into the host application
    });
    }
    

    boot-client.jsx:

    // Grab the state from a global injected into server-generated HTML
    const {id, initialReduxState, authenticationToken, config, server, userLocale } = window;
    
    if (server) {
    
    
    // Get the application-wide store instance, prepopulating with state from the server where available.
    const store = configureStore(initialReduxState);
    // This code starts up the React app when it runs in a browser.
    ReactDOM.render(
        <Provider store={ store }>
            <FormResponder authenticationToken={authenticationToken} config={config} />
        </Provider>,
        document.getElementById('react-app')
    );
    
    
    }
    else {
    
        const store = configureStore();
        store.dispatch(getFormById(id, config, authenticationToken));
        store.dispatch(updateUserLocale(userLocale));
    
        render(
            <Provider store ={store}>
                <FormResponder authenticationToken={authenticationToken} config={config} />
            </Provider>,
            document.getElementById('react-app')
        ); // Take our FormBuilder component and attach it with DOM element "app"
    }
    

    所以现在我可以通过在 url 末尾添加 ?server=false 来简单地关闭服务器渲染,然后开始调试 :)

    【讨论】:

      【解决方案3】:

      找到适合我的解决方案: 我在最终的 renderToString 上插入了一个 try/catch。 在哪里捕获我发送一个带有错误的调度。

      更新了 boot-server.jsx

      params.domainTasks.then(() => {
              let html;
              try {
                  html = renderToString(app);
              }
              catch (err) {
                  store.dispatch(loadFormFailed( {message: err.toString() } ));
              }
      
              resolve({
                  html: html,
                  globals: {
                      initialReduxState: store.getState(), 
                      authenticationToken: params.data.authenticationToken, 
                      config: params.data.config,
                      disableReactServerRendring: false
                  }
              });
              }, reject);
              // Also propagate any errors back into the host application
          });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-30
        • 2013-04-20
        • 2017-04-10
        • 1970-01-01
        • 1970-01-01
        • 2018-04-19
        • 2023-04-09
        相关资源
        最近更新 更多