ReactJS服务器端渲染单页面应用程序

时间:2015-07-30 15:55:56

标签: python django reactjs single-page-application serverside-javascript

我已经完成了什么

  • 我有一个完全用React.JS构建的前端。
  • 所有业务逻辑都由Django处理,并由Django REST Framework通过API公开。
  • 我能够为不同的移动环境(通过Cordova的Android和iOS)构建
  • 可以通过我的Django项目访问Web应用程序(暴露api的方式相同),前端是通过webpack捆绑的相同ReactJS代码。
  • 该应用程序有一个入口点main.js,它是我的react.js组件和依赖项的捆绑版本,因此我的index.html通常如下所示:

    <body>
        <script type="text/javascript" src="/static/bundles/main-3997ad3476694c3c91cf.js"></script>
    </body>
    

我想做什么

  • 我想提供我的网络应用程序的服务器端呈现,让网络抓取工具在网络上正确索引我的应用程序(我不是在寻找移动版本的服务器端呈现)。

考虑到我的应用程序是单页应用程序,我该如何处理?我不想重新发明轮子也不想复制我的代码。我必须编写什么样的node.js服务器才能实现这种自动服务器端呈现?有没有办法直接在Django中提供服务器端渲染(通过一些工具读取和解释客户端显示的页面的最终结果并返回此原始html?)

1 个答案:

答案 0 :(得分:3)

您现在可能已经解决了问题,但我想分享我的解决方案。

我有一个非常相似的设置,到目前为止看起来效果很好。我基本上有一个django w / DRF后端api和同构React / Flux javascript应用程序。我还在python后端服务器旁边运行一个节点服务器,它只作为一个模板呈现&#39;服务。实质上,替换django render函数。

所以我只需用一个特殊的View替换django IsoView,它通过http调用节点服务器并返回渲染的html。

from rest_framework.renderers import JSONRenderer
import requests

class IsoView(View):

    def user_json(self):
        if self.request.user.is_anonymous():
            return {'anonymous': True}
        else:
            return UserSerializer(self.request.user, context={'request': self.request}).data

    @classmethod
    def render(cls, request, template, data):
        req_data = JSONRenderer().render(data)
        try:
            headers = {'content-type': 'application/json'}
            query_params = request.GET
            resp = requests.post(_build_url(request.path), params=query_params, data=req_data, headers=headers, timeout=0.1)
            reply = resp.json()

            if resp.status_code == 302:
                return redirect(reply.get('redirect'))

            if 'error' in reply:
                raise Exception("\n\nRemote traceback: {}".format(reply.get('traceback')))

        except requests.exceptions.RequestException as err:
            logger.warn('IsoView request exception: {}'.format(err))
            reply = {}

        return render(request, template, {
            'react': reply.get('result'),
            'data': data
        })

并像这样使用它:

class HomePage(IsoView):

    def get(self, request, *args, **kwargs):
        return self.render(request, 'app.html', {
            'user': json_data...
        })

这也假设一个django模板使用类似这样的东西

<html>
<head>
    <script>
        window.data = {{ data|json }};
    </script>
</head>
<body>{{ react|safe }}</body>
</html>

这样做是为了呈现从body标签中的节点返回的html,还会转储在window.data对象中的客户端上引导应用程序所需的json数据。

这是系统的一个非常简化的版本,但它应该可以工作。你应该小心window.data位上的XSS攻击,所以一定要逃避所有的json数据,但除此之外,你应该都很好。

然后,节点模板服务器看起来非常类似于您可以找到的任何服务器端反应教程。只是一个简单的快递应用程序。

或者,如果您渲染完整的... in节点并将其作为字符串返回,则根本不需要使用django模板。

希望有所帮助。