带有获取身份验证和访问令牌的 Reactjs,无法解析响应

Posted

技术标签:

【中文标题】带有获取身份验证和访问令牌的 Reactjs,无法解析响应【英文标题】:Reactjs with fetch for auth and access token, not able to parse response 【发布时间】:2017-10-08 09:39:45 【问题描述】:

我对 ReactJS 很陌生。

我正在使用 Chrome 浏览器。

我正在尝试使用 ReactJS 创建登录页面。该页面很简单,带有用户名和密码。身份验证发生在我们的 SSO 服务器上,这意味着我必须使用 fetch 调用在服务器上发布数据并获取 access_token 作为响应。

问题如下:

我没有在控制台中得到响应。但是,当我查看开发人员工具上的“网络”选项卡时,我可以看到包含所有必填字段的有效响应,其中包括 access_token。 现在确定我应该如何解析这个。

这是因为fetch 是异步调用吗?

这是我的整个页面代码。

P.S:部分代码未格式化。

import React, Component from 'react';
import '../App/App.css';
import FormGroup, FormControl, InputGroup from 'react-bootstrap';

class Auth extends Component 


    constructor(props) 
        super(props);
        this.state = 
            userid: '',
            password: '',
            accessToken: ''
        
    

    submit() 
        console.log('state', this.state);
        const BASE_URL = 'MY SSO URL';
        const params = 
            'grant_type': 'password',
            'username': this.state.userid,
            'password': this.state.password,
            'client_secret': 'secred',
            'client_id': 'client_id',
        ;
        const formData = new FormData();
        for (let p in params) 
            formData.append(p, params[p]);
        
        const headers = 
            'Access-Control-Allow-Origin': '*'
        ;
        const request = 
            method: 'POST',
            headers: headers,
            body: formData,
            mode: 'no-cors'
        ;

        fetch(BASE_URL, request)
            .then((response) => response.text())
            .then((responseText) => 
                console.log('text',responseText);
            )
            .catch((error) => 
                console.warn(error);
            );
        console.log('all done');
    

    render() 
        return (
            <div className="login">
                <div className="legend">Signin</div>
                <FormGroup>
                    <InputGroup>
                        <div className="input">
                            <FormControl
                                type="text"
                                placeholder="Enter User Id or email"
                                onChange=event => this.setState(userid: event.target.value)
                                onKeyPress=
                                    event => 
                                        if (event.key === 'Enter') 
                                            this.submit()
                                        
                                    
                            />
                        </div>
                        <div className="input">
                            <FormControl
                                type="password"
                                placeholder="enter password"
                                onChange=event => 
                                    console.log(event.target.value)
                                    this.setState(password: event.target.value)
                                
                                onKeyPress=
                                    event => 
                                        if (event.key === 'Enter') 
                                            this.submit()
                                        
                                    
                            />
                        </div>
                        <FormControl
                            type="submit"
                            onClick=() => this.submit()
                        />
                    </InputGroup>
                </FormGroup>
            </div>
        )
    

export default Auth;

我试过response.json(),这给出了错误:Unexpected end of input

【问题讨论】:

【参考方案1】:

至于fetch(…) 请求的前端 javascript 代码:

mode: 'no-cors'

删除它。这就是您的代码无法访问响应的确切原因。

你永远不会想做mode: "no-cors"。唯一真正做的就是告诉浏览器,永远不要让我的前端 JavaScript 代码访问来自这个请求的响应

const headers = 
    'Access-Control-Allow-Origin': '*'
;

也删除这些行。 Access-Control-Allow-Origin 是一个 response 标头。你永远不想在请求中发送它。唯一的效果是触发浏览器进行预检。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

我猜您尝试mode: 'no-cors' 并在请求中发送Access-Control-Allow-Origin 的原因是您之前尝试了没有这些的请求,并且您在浏览器控制台中收到一条错误消息,指出响应缺少@ 987654332@.

如果是这样,您无法通过更改前端 JavaScript 代码来解决此问题,除非更改代码以通过代理发出请求,如"No 'Access-Control-Allow-Origin' header is present on the requested resource" 的答案中所述。

或者您需要在您的BASE_URL 地址获取服务器的所有者,以配置服务器以在其响应中发送Access-Control-Allow-Origin


这里有一个更长的解释:

只有当您发出请求的服务器明确表明他们选择接收跨域请求时,您的浏览器才会让您的前端 JavaScript 代码访问来自跨域请求的响应,他们通过发送 @ 987654335@ 响应头在他们的响应中。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 有更多详细信息。

浏览器是唯一对跨域请求实施限制的客户端,并且它们仅在 Web 应用程序上实施。

这就是为什么即使您看到 请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,在您的 devtools 控制台中,Origin ... is not allowed access 消息,您仍然可以转到 devtools 中的“网络”选项卡并查看那里的响应。

那是因为服务器已经发送了响应并且浏览器已经接收到它,但是浏览器只是拒绝让你的前端 JavaScript 代码访问响应,因为发送响应的服务器没有选择跨- 通过发送Access-Control-Allow-Origin 响应头来发起请求。

当您从 curl 等发出请求时,您可以很好地获得响应的原因是,如果缺少 Access-Control-Allow-Origin 响应标头,除了浏览器之外,没有其他客户端会拒绝您的代码访问响应。但浏览器总是会的。

请注意,在这一切中,服务器都不会阻止或拒绝响应任何请求。服务器总是继续只接收请求并发送响应。唯一的区别在于服务器是否在响应中发送 Access-Control-Allow-Origin 标头。

【讨论】:

谢谢,您在使用 no-cors 和标题 'Access-Control-Allow-Origin': '*' 方面很准确,如果我不使用这些,我会出错。但是我的 curl 命令运行良好,没有任何问题,因此我有点困惑前端代码中缺少什么。 这是我删除标头和 no-cors 后得到的结果“请求的资源上不存在'Access-Control-Allow-Origin'标头。因此不允许使用Origin'localhost:3000'访问。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。但是 curl 一切都很好,没有问题。 所以是的,问题在于 BASE_URL 服务器没有发送 Access-Control-Allow-Origin 响应标头。我更新了上面的答案以添加更长的解释。它在 curl 中起作用的原因是 curl 不会根据是否找到 Access-Control-Allow-Origin 响应标头来改变其行为。但是浏览器可以。

以上是关于带有获取身份验证和访问令牌的 Reactjs,无法解析响应的主要内容,如果未能解决你的问题,请参考以下文章

身份验证令牌和授权如何在 reactjs 中工作?

无法读取未定义的 reactjs JWT 身份验证的属性“令牌”

Microsoft 认知服务 - 身份验证问题,无法获取访问令牌

ReactJS 从 API fetch 中获取令牌字符串

无法根据访问令牌对用户进行身份验证 - MS Graph API C#

带有 Okta 的 Gitlab 访问令牌