Express和React Routes如何处理来自浏览器的初始GET请求?

时间:2019-01-21 00:54:27

标签: javascript node.js reactjs express react-router

我对反应世界和整个堆栈世界还是陌生的,但是我一直在不停地寻找以下问题的答案,并且一定会得到一些指导。

我正在使用React和Express创建一个应用程序。它需要身份验证,所以我打算使用Passport进行帮助。客户端JS使用React Routers浏览网站。没关系,但是我的问题是浏览器发出的初始GET请求。

我将首先描述我的特定应用程序要求,然后概括我不了解的内容。

正如我所说,我的应用程序需要OAuth2身份验证。如果您尝试在我的网站上获取路径,但尚未登录,则只需加载登录页面即可。如果您已登录,请照常加载并找到路径。与facebook类似,我希望登录URL与“提要”页面相同。类似于facebook.com的“ /”路由是登录页面还是新Feed(取决于您是否登录)的方式,我希望得到同样的结果。

据我了解,Passport通过检查请求标头在后端进行身份验证。因此,我了解到我应该拥有某种中间件,该中间件说“如果用户已登录,请继续进行操作,否则将呈现登录页面”……这是如何完成的?代码是什么样的?我对Express的唯一经验来自于一个介绍类,该类使用res.render发送回HTML文件,并将其通过某些模板引擎(如把手)传递。但是我不知道它如何与反应路线一起工作。我还会使用res.render()吗?还有吗

比方说,我的index.html具有根div来注入反应。如果我不得不猜测的话,我将把带有路由的.js文件发送回index.html页面,并在后端以某种方式将我希望它与我的响应路由匹配的路由(无论是登录名还是用户名)发送回去要求)?

更一般地说,我想我只是对如何使用React路由向网站的初始请求感到困惑。 1)服务器如何与所有内容交互以呈现我所要求的? 2)代码将是什么样子。我对React的唯一经验是来自一个基本的Udemy课程,该课程仅使用“ react-scripts start”来呈现页面。

花了整整一天的时间搜索这个问题后,我才想到了SSR,这是它自己的难题,我甚至不确定它是否需要帮助。是吗?

我显然缺少一些基本知识,因为这确实使我绊倒了,因此,如果您有任何学习的资源,只需将其发布即可。谢谢!

3 个答案:

答案 0 :(得分:1)

我认为您正在苦苦挣扎的根本鸿沟源于大量的“入门课程”,它们将整个浏览器客户端推到了应用服务器中,以使事情迅速启动并运行,例如,Node服务器渲染了整个React应用并以API的身份运行...

 // Ajax request from React app to: http://example.com/api

app.use('/api/*'),()=> {
   res.send({ <!-- some JSON object -->})
})

// User visits in browser: http://example.com/**/*     

app.use('/*',()=>{
   res.render(<!-- entire React App sent to browser -->)
})

第一个请求(假设用户不访问/ api / *)只会发送React包。客户端中进一步的用户导航通常会将来自React应用的XHR请求(或打开的WebSocket)发送到在同一节点程序上运行的Express路由。

在许多情况下,将程序的这些部分分开是有意义的,例如,可以从与请求数据的位置完全不同的位置传递响应。这样做的原因很多,但是优化计算资源以满足其对CPU,内存,网络等的不同需求以及代码/部署的可管理性是我的主要理由。

例如...

  • 用户访问:http://example.com *

    1. Nginx,Apache,一个“云代理” .etc将流量定向到静态React捆绑包,该捆绑包没有身份验证,也从未与您的Node服务器联系。
    2. 如果用户以前具有身份验证功能,那么他们将在本地存储中拥有令牌(如果您使用JWT进行身份验证),并且您的React应用程序将配置为始终在首次加载时始终检查这些令牌。
    3. 如果用户拥有令牌,它将在后台发送Ajax请求,并将令牌作为标头载体,并发送回用户数据,然后将其重定向到“授权页面”,例如您提到的FB feed。 li>
    4. 如果他们没有令牌,或者令牌认证失败,那么React将把他们重定向到“登录”或“注册”页面

反应

基本上高的响应会影响浏览器的本机“位置”功能(域名后显示的内容)。因此,初始页面加载后的所有事件(按钮单击等)都完全由React在内部处理,并使用这些路由来确定要显示的内容或要通过Ajax(XHR)从API提取的数据。

如果用户执行硬页重新加载,则该请求将返回到服务器,并将再次执行整个周期

反应路由器

允许您同时做两件事...

  1. 操纵浏览器LocationHistory对象。
  2. 通过检测变化和发送事件,在其他地方使用“历史记录”和“位置”信息。

SSR

我只是玩弄SSR,所以我可以与之交谈,但是它提供了极低的初始渲染延迟,可以在1个网络请求中完成,因此您想在程序的重要区域使用它。< / p>

不确定是否可以回答您的问题,但是请告诉我您是否希望我详细说明什么或提供一些更详细的资源。

答案 1 :(得分:0)

我了解您的努力,因为在将前端与后端(尤其是React和Node)结合时必须自己解决。首先,我们知道浏览器/客户端将始终向服务器发起请求,因此React Router如何控制路由?好吧,它实际上很简单,您所要做的就是从快递服务器的任何路径返回整个react app。该代码将如下所示:

const express = require('express');
const app = express();

app.get('/*', (req, res, next) => {
  // Return React App index.html
});

app.listen(3000);

一旦React应用在用户浏览器上呈现(不必担心路径,因为React将基于您在客户端编写的代码根据URL自动呈现,因此它还将处理身份验证与提要页面)当它扫描您的本地存储,Cookie等)时,它将控制路由,而不是发送到快递服务器的请求。但是,当我们从服务器请求数据时会发生什么情况,它会在每个路由上返回react app,因此我们需要设置一个api路由来处理任何数据请求。

app.get('/api/v1/*', (req, res, next) {
  // Return some data in json format 
});

希望这能使您了解所需的内容。

答案 2 :(得分:0)

对于经验较少的开发人员来说,SSR有点混乱,让我们暂时忘记它。

假设前端JavaScript(React)和后端Javascript(NodeJS)是两个单独的应用程序,并且它们通过API相互通信,将会更容易。

根据您是否登录

,此处显示显示登录组件和 Feed 组件的代码。
import React, { Component } from "react";
import axios from "axios";

class Home extends Component {
  constructor() {
    const accessToken = localStorage.getItem("accessToken");
    this.state = {
      accessToken,
      feeds: []
    };
  }

  componentDidMount() {
    if (this.state.accessToken) {
      axios(`api/feeds?accessToken=${this.state.accessToken}`).then(({ data }) => {
        this.setState({
          feeds: data
        });
      });
    }
  }

  render() {
    if (this.state.accessToken) {
      return <FeedsComponent feeds={this.state.feeds} />;
    }
    return <LoginComponent />;
  }
}

这是您的后端

const express = require("express");

const app = express();

app.get('/api/feeds', (req, res, ) => {
    const feeds = [
        {},
        {}
    ]
    res.status(200).json(feeds);
});

app.listen(3001);

请记住,它们是两个单独的应用程序,它们可以位于两个不同的文件夹,不同的服务器,不同的端口中。