12.8&12.9[java exp4][debug]跨域问题原因详解

pro1

在配置CORS(跨源资源共享)时,当allowCredentials设置为true时,allowedOrigins不能包含通配符*。这是因为当允许凭据(如cookies、HTTP认证信息等)时,响应头中的Access-Control-Allow-Origin不能是一个通配符,而必须是具体的源。

要解决这个问题,有几种方法:

明确列出允许的源:如果你知道哪些特定的源需要访问你的API,可以将这些源明确地添加到allowedOrigins列表中。

使用allowedOriginPatterns:Spring 5.3引入了allowedOriginPatterns属性,它允许你使用模式来匹配多个源,同时支持凭据。

为了确保CORS和凭据支持的正确性,建议进行一些调整。特别是当你在后端配置了CORS并且允许凭据时,Nginx的配置也需要确保正确传递所有必要的请求头。

  1. 前端服务器 (例如Nginx或Apache):

    • 用于托管前端静态文件。
    • 可以配置反向代理,将某些请求转发到8081服务器。

关键点

  • 前端服务器的作用:

    • 托管前端静态文件(HTML、CSS、JavaScript等)。
    • 可以配置反向代理,以便前端应用可以通过相同的域名访问不同的后端服务。
  • CORS配置:

    • 需要在8081服务器上配置CORS,允许来自前端服务器的请求。
    • 如果前端服务器使用反向代理,那么前端应用实际上是在与前端服务器通信,而不是直接与8081服务器通信。

listen 80; 的作用

基本功能
  • 监听端口listen 80; 指令告诉 Nginx 监听 80 端口上的所有传入 HTTP 请求。
  • 默认端口:HTTP 协议的默认端口是 80,因此大多数情况下,客户端(如浏览器)在访问网站时不显式指定端口号时,默认会使用 80 端口。

当你直接在浏览器中输入 http://localhost 并按下回车键时,会发生以下过程:

  1. DNS 解析

    • 浏览器首先尝试解析 localhost 到一个 IP 地址。通常,localhost 会被解析为 127.0.0.1::1(IPv6)。
  2. 建立连接

    • 浏览器与本地主机(即 127.0.0.1::1)的 80 端口建立 TCP 连接。

发送 HTTP 请求

  • 浏览器向 Nginx 发送一个 HTTP GET 请求,类似于以下内容:

    GET / HTTP/1.1
    Host: localhost
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9

  1. Nginx 处理请求

    • Nginx 收到请求后,会根据 listenserver_name 指令来匹配合适的 server 块。
    • 对于 listen 80;server_name localhost; 的配置,Nginx 会选择这个 server 块来处理请求。
  • HTTP 默认端口 (80):

    • HTTP 协议的标准端口是 80。这意味着当浏览器尝试通过 HTTP 访问一个网站时,默认情况下会连接到该网站服务器的 80 端口。
    • 例如,当你在浏览器中输入 http://example.com 时,实际上是在请求 http://example.com:80
  • 前端开发默认端口 (3000 或其他):

    • 在开发阶段,前端框架(如 React、Vue.js、Angular 等)通常会在本地启动一个开发服务器,以便开发者可以在浏览器中实时查看和测试应用。
    • 这些开发服务器默认使用特定的端口号(通常是 3000),但这并不是标准的 HTTP 端口,而是为了方便开发而选择的一个常见端口。
    • 例如,如果你使用 Create React App 启动了一个 React 应用,它可能会在 http://localhost:3000 上运行。
  • 开发 vs 生产:

    • 开发环境: 在开发过程中,前端应用通常在一个独立的端口上运行(如 3000)。这使得多个项目可以同时在同一台机器上运行而不发生冲突。
    • 生产环境: 当应用部署到生产服务器时,通常会被配置为监听标准的 HTTP 端口(80)或 HTTPS 端口(443)。这样,用户可以通过常规的 URL 访问应用,而不需要指定额外的端口号。
  • 代理和反向代理:

    • 在某些情况下,前端应用可能需要与后端 API 进行通信。为了简化开发过程并解决跨域问题,前端开发服务器可以配置代理,将特定路径的请求转发到后端服务。
    • 在生产环境中,Nginx 或其他反向代理服务器常用于处理来自客户端的请求,并将其转发到相应的后端服务。这种设置可以帮助管理不同的服务和端口,提高系统的整体性能和安全性。
    • 前端应用在 http://localhost:3000 上运行。
    • 后端 API 在 http://localhost:5000 上运行。
    • 你可以配置前端开发服务器将 /api 路径的请求代理到 http://localhost:5000,从而避免跨域问题。
  • 生产阶段:

    • 前端静态文件部署在 Nginx 上,并监听标准的 HTTP 端口(80)。
    • 后端 API 部署在另一个服务器上,或者同样由 Nginx 反向代理处理。
    • 用户访问 http://example.com 时,Nginx 会根据配置将请求路由到正确的后端服务。

Nginx 可以通过配置来解决跨域问题,主要是通过设置适当的 HTTP 头来允许特定的跨域请求。以下是一些常见的配置方法:

基本 CORS 配置

在 Nginx 中,你可以通过 add_header 指令来添加必要的 CORS 头信息。以下是一个基本的示例:

server {
    listen 80;
    server_name localhost;

    location /api/ {
        # 允许所有来源的请求
        add_header 'Access-Control-Allow-Origin' '*';
        # 允许的方法
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        # 允许的头部字段
        add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';

        # 处理预检请求 (OPTIONS)
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            add_header 'Content-Length' 0;
            return 204;
        }

        # 转发请求到后端服务器
        proxy_pass http://localhost:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  1. add_header 'Access-Control-Allow-Origin' '*';

    • 作用:允许所有来源的请求。
    • 安全性考虑 :使用 * 允许所有来源可能会带来安全风险。建议根据实际情况指定具体的域名,例如 add_header 'Access-Control-Allow-Origin' 'http://frontend.example.com';
  2. add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

    • 作用:指定允许的 HTTP 方法。
    • 含义:允许 GET、POST 和 OPTIONS 请求。
  3. add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';

    • 作用:指定允许的请求头部字段。
    • 含义 :允许 OriginContent-TypeAcceptAuthorization 头部字段。
  4. 处理预检请求 (OPTIONS)

    • 作用:浏览器在发送实际请求之前,会先发送一个 OPTIONS 请求来检查是否允许真正的请求。

    • 实现

      if ($request_method = 'OPTIONS') {
          add_header 'Access-Control-Max-Age' 1728000;
          add_header 'Content-Type' 'text/plain charset=UTF-8';
          add_header 'Content-Length' 0;
          return 204;
      }
      
    • 含义:如果请求方法是 OPTIONS,则返回 204 No Content 状态码,并设置缓存时间和其他必要的头部信息。

  5. 转发请求到后端服务器

    • 作用:将实际的请求转发到后端服务器。

    • 实现

    diff 复制代码
    proxy_pass http://localhost:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
跨域请求的两种情况
a. 简单请求(Simple Requests)
  • 定义:满足以下条件之一的请求被认为是简单请求:

    • 使用 GET、HEAD 或 POST 方法。
    • Content-Type 只能是 application/x-www-form-urlencodedmultipart/form-datatext/plain
    • 没有使用自定义头部字段。
  • 行为

    • 浏览器直接发送请求到目标服务器。
    • 如果响应中包含适当的 CORS 头,则浏览器允许前端应用处理响应;否则,浏览器会阻止响应并抛出错误。
预检请求(Preflight Requests)
  • 定义:不满足简单请求条件的请求会被视为预检请求。

    • 使用非简单方法(如 PUT、DELETE)。
    • Content-Type 包含其他值(如 application/json)。
    • 添加了自定义头部字段。
  • 行为

    • 浏览器首先发送一个 OPTIONS 请求到目标服务器,以询问服务器是否允许实际请求。
    • 服务器必须在响应中包含适当的 CORS 头来确认允许该请求。
    • 如果服务器允许,浏览器才会发送实际的请求;否则,浏览器会阻止实际请求并抛出错误
响应中的 CORS 头
  • 目的:告诉浏览器服务器允许哪些来源、方法和头部字段进行跨域请求。
  • 关键作用
    • Access-Control-Allow-Origin :指定允许访问的源。例如,Access-Control-Allow-Origin: http://frontend.example.com
    • Access-Control-Allow-Methods :指定允许的 HTTP 方法。例如,Access-Control-Allow-Methods: GET, POST, PUT, DELETE
    • Access-Control-Allow-Headers :指定允许的请求头部字段。例如,Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization
    • Access-Control-Allow-Credentials :指示是否允许发送凭证(如 cookies)。例如,Access-Control-Allow-Credentials: true
    • Access-Control-Max-Age :指定预检请求的结果可以被缓存的时间。例如,Access-Control-Max-Age: 1728000(20 天)。
2. 预检请求(OPTIONS 请求)
  • 过程

    1. 浏览器发送 OPTIONS 请求:浏览器在发送实际请求之前,先发送一个 OPTIONS 请求到目标服务器,以询问服务器是否允许实际请求。
    2. 服务器响应:服务器必须在响应中包含适当的 CORS 头来确认允许该请求。
    3. 浏览器决策:如果服务器允许,浏览器才会发送实际的请求;否则,浏览器会阻止实际请求并抛出错误。

CORS

什么是 CORS ?一文搞懂 CORS 跨域原理!零基础入门到精通,收藏这一篇就够了-CSDN博客

当一个网页向不同源发出请求时,CORS 会通过以下几个步骤来处理:

预检请求(Preflight Request):对于某些类型的请求(如使用 HTTP 方法 PUT、DELETE,或者请求带有非简单头部),浏览器会首先发送一个 OPTIONS 请求,这个请求称为"预检请求"。服务器收到这个请求后,会返回一个响应头部,指明实际请求是否被允许。

实际请求(Actual Request):如果预检请求通过,浏览器会继续发送实际的请求。

响应头部(Response Headers):服务器在响应中会包含一些特定的 CORS 头部,如 Access-Control-Allow-Origin,以指示哪些域名可以访问资源。

什么是 Origin?

Origin,翻译为 源(域),在 CORS 上下文中 Origin 由三个元素组成:

Origin = 协议 + 域名 + 端口   

对于复杂请求,浏览器会首先发送一个 OPTIONS 请求,包含以下头部字段:

Origin:指示请求的源。

Access-Control-Request-Method:指示实际请求将使用的方法。

Access-Control-Request-Headers:指示实际请求将包含的自定义头部。

服务器收到预检请求后,会返回一个响应,包含以下头部字段以指示是否允许请求:

Access-Control-Allow-Origin:表明允许访问资源的源,可以是具体的源或通配符 *;

Access-Control-Allow-Methods:表明允许的方法,如 GET, POST, PUT, DELETE;

Access-Control-Allow-Headers:表明允许的自定义头部;

Access-Control-Allow-Credentials:表明是否允许发送凭据(如 Cookies);

Access-Control-Expose-Headers:表明哪些头部可以作为响应的一部分被访问;

Access-Control-Max-Age:表明预检请求的结果可以被缓存的时间,单位是秒;

如果预检请求通过,浏览器会继续发送实际请求。

可以设置一个同源的代理服务器,所有的跨域请求都先发送到这个代理服务器,然后由它转发给目标服务器。这样可以避免浏览器的同源策略限制,因为从浏览器的角度看,所有请求都是同源的。

  1. 修改浏览器设置(仅限开发/测试)

    • 某些浏览器允许通过命令行参数或配置文件禁用安全检查。例如,Chrome可以通过启动参数--disable-web-security来临时禁用同源策略。但这只适合本地开发和测试,绝不应该在生产环境中这样做。
  2. 使用浏览器扩展

    • 存在一些浏览器扩展可以帮助开发者绕过跨域限制,如CORS Unblock或Allow CORS: Access-Control-Allow-Origin。这些扩展可以在开发过程中帮助调试API调用,但同样不建议在生产环境中使用。
  3. 服务器端配置CORS

    • 如之前所述,最正确的方式是通过服务器端配置CORS响应头来允许特定来源的跨域请求。这是唯一一种既安全又符合标准的做法,因为它是在服务器控制之下进行的,并且不会影响浏览器的安全机制。
  4. JSONP (仅适用于GET请求)

    • JSONP是一种较老的技术,它通过动态创建<script>标签来发起跨域请求。由于<script>标签不受同源策略限制,所以可以用来加载来自不同源的JavaScript代码。但是,JSONP只支持GET请求,而且存在一定的安全隐患,因此现代应用中较少使用。
  5. WebSocket

    • WebSocket协议不受同源策略限制,可以用于实现跨域通信。不过,这适用于实时双向通信的场景,而不是普通的HTTP请求。
  6. 防止数据泄露:

    • 防止恶意网站通过JavaScript获取用户在其他网站上的敏感信息。
    • 例如,如果一个银行网站和一个恶意网站不在同一个源上,恶意网站无法通过JavaScript读取银行网站中的用户会话信息或交易记录。
  7. 保护用户隐私:

    • 确保用户的数据不会被意外或恶意地传递给未经授权的第三方。
    • 例如,社交媒体平台上的用户数据不应被其他网站轻易获取。
  8. 防止CSRF攻击 (Cross-Site Request Forgery):

    • 防止攻击者诱导用户在已登录的状态下向某个网站发送恶意请求。
    • 例如,即使用户已经登录了电子邮件服务,恶意网站也不能通过JavaScript自动发送邮件。

场景 : 用户在一个银行网站 (https://bank.com) 上登录并查看账户余额。同时,用户打开了一个恶意网站 (https://malicious-site.com)。

请求的发送情况
  1. 用户在 https://bank.com 登录:

    • 用户输入用户名和密码,并提交表单。
    • 浏览器向 https://bank.com/api/login 发送POST请求。
    • 银行服务器验证凭据后,返回一个包含会话cookie的响应。
  2. 用户访问 https://malicious-site.com:

    • 用户浏览恶意网站。
    • 恶意网站尝试通过JavaScript获取银行账户余额。
  3. 恶意网站发送跨域请求:

    • 恶意网站使用JavaScript发起一个GET请求到 https://bank.com/api/balance
  • 浏览器行为 :

    • 浏览器检测到这是一个跨域请求(源不同),并且请求携带了凭证(Cookie)。
    • 浏览器自动添加 Origin 头,并发送预检请求(OPTIONS)到 https://bank.com/api/balance
  • 实际请求 :

    • 由于预检响应中没有允许 https://malicious-site.com,浏览器阻止实际的GET请求发送到 https://bank.com/api/balance
  • 最终结果 :

    • 恶意网站无法获取用户的账户余额信息。

场景 : 用户在一个社交媒体平台 (https://socialmedia.com) 上浏览个人资料,并在同一时间打开了一个论坛网站 (https://forum.com)。

请求的发送情况
  1. 用户在 https://socialmedia.com 浏览个人资料:

    • 用户访问自己的个人资料页面。
    • 社交媒体服务器返回用户的个人信息。
  2. 用户访问 https://forum.com:

    • 用户浏览恶意论坛。
    • 恶意论坛尝试通过JavaScript获取用户的社交媒体个人信息。
  3. 恶意论坛发送跨域请求:

    • 恶意论坛使用JavaScript发起一个GET请求到 https://socialmedia.com/api/user-info
  • 实际请求 :

    • 由于预检响应中没有允许 https://forum.com,浏览器阻止实际的GET请求发送到 https://socialmedia.com/api/user-info
  • 最终结果 :

    • 恶意论坛无法获取用户的个人信息。
  • 浏览器会缓存预检请求的结果,以减少不必要的网络开销。

  • 如果后续的请求与之前的预检请求匹配,则可以直接发送实际请求,而不需要再次发送预检请求。

缓存有效期:

  • 预检请求的响应头中包含Access-Control-Max-Age字段,该字段指定了预检请求结果的有效期(以秒为单位)。
  • 在有效期内,浏览器可以重用预检请求的结果,不再发送新的预检请求。

具体流程

  1. 首次跨域请求:

    • 用户发起一个需要预检的跨域请求(例如,使用PUT方法或包含自定义头)。
    • 浏览器检测到这是一个需要预检的请求,先发送一个OPTIONS请求到目标服务器。
    • 目标服务器返回预检响应,包含CORS相关的头信息,如Access-Control-Allow-OriginAccess-Control-Allow-Methods等。
    • 浏览器检查预检响应中的头信息,如果允许该请求,则发送实际的跨域请求。
  2. 后续跨域请求:

    • 如果用户在预检响应的有效期内再次发起相同的跨域请求(相同的源、方法、头信息),浏览器会直接发送实际请求,而不必再发送预检请求。
    • 这是因为浏览器已经缓存了上次预检请求的结果,并且这些请求参数没有变化。

CORS 响应头详解

为了更好地理解预检请求和缓存机制,以下是一些关键的CORS响应头:

  • Access-Control-Allow-Origin:

    • 指定允许访问资源的源。
    • 示例: Access-Control-Allow-Origin: http://frontend.com
  • Access-Control-Allow-Methods:

    • 指定允许的HTTP方法。
    • 示例: Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
  • Access-Control-Allow-Headers:

    • 指定允许的自定义头。
    • 示例: Access-Control-Allow-Headers: Content-Type, X-Custom-Header
  • Access-Control-Allow-Credentials:

    • 指定是否允许携带凭证(如cookies)。
    • 示例: Access-Control-Allow-Credentials: true
  • Access-Control-Max-Age:

    • 指定预检请求的结果缓存时间(秒)。
    • 示例: Access-Control-Max-Age: 3600

缓存位置:

  • 浏览器内存: 预检请求的结果(包括CORS响应头)存储在浏览器的内存中。
  • 生命周期 : 缓存的有效期由Access-Control-Max-Age头指定,通常以秒为单位。

缓存内容:

  • 每个跨域请求的目标服务器和路径组合会有独立的缓存条目。
  • 浏览器会根据请求的源、方法、头信息等参数来匹配缓存条目。

具体流程

  1. 首次跨域请求:

    • 用户发起一个需要预检的跨域请求。
    • 浏览器检测到这是一个需要预检的请求,先发送一个OPTIONS预检请求到目标服务器。
    • 目标服务器返回预检响应,包含CORS相关的头信息。
    • 浏览器检查预检响应中的头信息,如果允许该请求,则发送实际的跨域请求。
    • 浏览器将预检响应的结果缓存起来。
  2. 后续跨域请求:

    • 如果用户在预检响应的有效期内再次发起相同的跨域请求,浏览器会直接发送实际请求,而不必再发送预检请求。
    • 浏览器会根据请求的源、方法、头信息等参数来匹配缓存条目。
    • 如果找到匹配的缓存条目并且仍在有效期内,则使用缓存的结果。
  3. 多个目标服务器:

    • 每个目标服务器的CORS信息会被分别缓存。
    • 浏览器会为每个不同的目标服务器和路径组合维护独立的缓存条目。
  • location /:

    • 定义了一个位置块,匹配所有以 / 开头的请求。
  • proxy_pass http://localhost:3000;:

    • 将匹配到的请求代理到 http://localhost:3000,即运行在本地 3000 端口的前端服务器。
  • proxy_http_version 1.1;:

    • 设置代理请求使用的 HTTP 版本为 1.1。这有助于支持长连接和更高效的通信。
  • proxy_set_header Upgrade $http_upgrade;:

    • 将客户端请求中的 Upgrade 头传递给后端服务器。这通常用于 WebSocket 协议的升级。
  • proxy_set_header Connection 'upgrade';:

    • 将客户端请求中的 Connection 头设置为 upgrade,以便支持协议升级(如 WebSocket)。
  • proxy_set_header Host $host;:

    • 将客户端请求中的 Host 头传递给后端服务器。这有助于后端服务器正确处理请求,特别是在有多个虚拟主机的情况下。
  • proxy_cache_bypass $http_upgrade;:

    • 如果客户端请求中有 Upgrade 头,则不使用缓存,直接将请求转发给后端服务器。这通常用于避免缓存 WebSocket 请求。
  1. proxy_set_header Host $host;:

    • 将客户端请求中的 Host 头传递给后端服务器。这样后端服务器可以看到原始请求的主机名。
  2. proxy_set_header X-Real-IP $remote_addr; (虽然你没有配置这个,但可以添加):

    • 将客户端的真实 IP 地址传递给后端服务器。后端服务器可以通过 X-Real-IP 头获取客户端的真实 IP 地址。
  3. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; (虽然你没有配置这个,但可以添加):

    • 将客户端的 IP 地址添加到 X-Forwarded-For 头中。如果请求经过多个代理,X-Forwarded-For 头会包含所有中间代理的 IP 地址。

Content-Type: application/json

  • 指示请求体(payload)的内容类型。在这个例子中,application/json表示请求体是以JSON格式编码的数据。服务器会根据这个头部来解析接收到的数据
  1. Referer: http://localhost:3000/

    • 表示发出请求的页面的URL。这有助于服务器了解请求是从哪个页面发起的,有时用于安全检查或统计分析。这里的http://localhost:3000/表明请求来自本地运行的一个Web应用,可能是开发环境中的一个前端应用。

前端调试

  1. Name:请求的名称,通常是请求的URL。
  2. Status:请求的状态码,例如200表示请求成功,404表示请求的资源未找到。
  3. Type:请求的类型,例如Fetch/XHR表示通过XMLHttpRequest或Fetch API发起的请求,Doc表示HTML文档,CSS表示样式表,JS表示JavaScript文件,Font表示字体文件,Img表示图像文件,Media表示媒体文件,Manifest表示清单文件,WS表示WebSocket连接,Wasm表示WebAssembly模块,Other表示其他类型的请求。
  4. Initiator:发起请求的实体,例如JavaScript代码、HTML标签等。
  5. Size:请求的大小,通常以字节为单位。
  6. Time:请求的时间,通常包括请求的开始时间、结束时间以及持续时间。
  7. Fulfilled by:请求是由哪个服务器响应的,例如CDN(内容分发网络)。

cors问题详情

浏览器发送请求后:

前端界面

添加注册弹窗:使用 useState 来控制弹窗的显示与隐藏。

添加注册表单:在弹窗中添加用户名和密码输入框,以及提交按钮。

处理注册逻辑:编写处理注册逻辑的函数,包括发送注册请求和处理响应。

错误提示:在注册过程中,如果出现错误,需要给出相关提示。

添加了 isRegisterModalOpen 状态来控制注册弹窗的显示与隐藏。

添加了 registerUsername 和 registerPassword 状态来存储注册表单中的用户名和密码。

添加了 registerError 和 registerLoading 状态来存储注册过程中的错误信息和加载状态。

添加了 handleRegisterSubmit 函数来处理注册逻辑。

在登录表单下方添加了一个"注册"按钮,点击后打开注册弹窗。

在注册弹窗中添加了注册表单和关闭按钮。

pro2

有点蠢,就是每个函数块最后要加分号;

最后return好像不用

遮罩层:

添加了一个全屏的 div 作为遮罩层,覆盖整个页面。

遮罩层的样式设置为 position: fixed, top: 0, left: 0, width: 100%, height: 100%, backgroundColor: 'rgba(0, 0, 0, 0.5)',使其覆盖整个视口并带有半透明的黑色背景。

设置 zIndex: 1000 确保遮罩层在其他内容之上。

点击遮罩层时,会调用 setIsRegisterModalOpen(false) 关闭弹窗。

弹窗:

弹窗的 zIndex 设置为 1001,确保它在遮罩层之上。

点击弹窗内部的元素不会触发遮罩层的点击事件,从而保持弹窗的焦点。

通过这种方式,当弹窗打开时,用户将无法与背景内容进行交互,只能操作弹窗内的内容。

单个根节点限制:

JSX 要求每个 JSX 表达式只能有一个根节点。如果你直接返回多个相邻的元素,JSX 会报错,因为这违反了单个根节点的规则。

Fragment 的作用:

使用 <> 或 <React.Fragment> 可以将多个元素包裹在一起,而不会在 DOM 中引入额外的节点。这使得代码更简洁,并且不会影响布局或样式。

通常情况下,你需要在全局异常处理器中捕获并处理这个异常,以便返回适当的错误响应。以下是一个简单的全局异常处理器示例:

pro3

无法捕获来自后端的错误信息,直接进入catch块

打印err信息::

??????未解之谜

、这不是已经接收到了吗???

懂了,并不是按照json格式组织的,正确的响应是这样的

是按Json格式组织的

正确的ResponseEntity的泛型是DTO的JAVA类

之前一直没留意,而在错误类里,就是String,不是对象类,没组织成JSON格式,所以错了

pro4

fetch 函数的 options 参数类型与你在 fetchWithAuth 方法中传递的对象类型不完全匹配。具体来说,RequestInit 类型中的一些属性(如 next)在标准的 fetch 请求中并不适用,导致类型不匹配。

为了确保类型兼容性,你可以采取以下几种方法之一:

移除不兼容的属性:确保传递给 fetch 的 options 对象只包含 RequestInit 类型中定义的属性。

自定义类型:定义一个自定义类型,继承 RequestInit 并添加额外的属性。

类型断言:使用类型断言来告诉 TypeScript 你传递的对象符合 RequestInit 类型。

在 TypeScript 中,fetch 函数的 options 参数类型被定义为 RequestInit。RequestInit 是一个接口,定义了可以传递给 fetch 的各种选项,例如 method、headers、body 等。然而,RequestInit 接口中并没有 priority 属性。

当你在 fetchWithAuth 方法中传递一个包含 priority 属性的对象时,TypeScript 会报错,因为这个属性不在 RequestInit 接口中定义。

在上面的例子中,options 对象包含了一个 priority 属性,而 RequestInit 接口中并没有 priority 属性。因此,TypeScript 会报错,提示类型不匹配。

相关推荐
lzhdim1 分钟前
2、C#基于.net framework的应用开发实战编程 - 设计(二、二) - 编程手把手系列文章...
开发语言·c#·.net
山山而川粤12 分钟前
时间管理系统|Java|SSM|JSP|
java·开发语言·后端·学习·mysql
冒泡P14 分钟前
【Lua热更新】上篇
开发语言·数据结构·unity·c#·游戏引擎·lua
Q_192849990620 分钟前
基于Spring Boot的远程教育网站
java·spring boot·后端
我不想写昵称29 分钟前
【基础篇】1. JasperSoft Studio编辑器与报表属性介绍
java·后端·报表·jasperreport
爱学测试的李木子1 小时前
性能】JDK和Jmeter的安装与配置
java·开发语言·软件测试·测试工具·jmeter
百年孤独_1 小时前
高阶:基于Python paddleocr库 提取pdf 文档高亮显示的内容
开发语言·python·pdf
softshow10261 小时前
Solon 集成 activemq-client
java·activemq·java-activemq
组合缺一1 小时前
solon 集成 activemq-client (sdk)
java·solon·activemq
小马超会养兔子1 小时前
如何写一个转盘
开发语言·前端·vue