【问题标题】:GET request to port 81 using axios (or even js native fetch)使用 axios GET 请求到端口 81(甚至是 js 本机 fetch)
【发布时间】:2020-05-12 12:30:56
【问题描述】:

我有一个在 81 端口上运行的 Node.js API,并希望像这样从 JavaScript 访问端点:

function fetchFromApi() {
    const axios = require('axios');
    console.log('using port 81',axios.defaults);
    axios.request({
        method: 'get',
        url:'/api/getAccountList',
        port: 81, // port options is not valid - this does not have the desired result
    })
    .then( response => {
        console.log(response);
        const data = response.data;
        const errors = (data.errors) ? data.errors : false;
        if (errors) {
            setErrors(errors);
        }
    })
    .catch( reason => {
        console.log(reason);
    });
}

chrome 开发者工具中的网络选项卡显示此请求仍转到端口 80。

当我尝试对 axios 请求中的整个协议、端口、主机和 url 进行编码时,我收到一个 CORS 错误:

axios.get('http://localhost:81/api/getAccountList')

错误是:

在“http://localhost:81/api/getAccountList”访问 XMLHttpRequest 来自原点“http://localhost”已被 CORS 策略阻止:否 请求中存在“Access-Control-Allow-Origin”标头 资源。

我的 API 服务器是一个简单的 Node.js 服务器:

const express = require('express');
const app = express();
const port = 81;
app.get('/api/getAccountList', (req, res) => {
    const userIdBy = req.params.userIdBy;
    const apiToken = req.params.apiToken;

    if (!(userIdBy && apiToken)) {
        res.status(200).json({errors:['Missing credentials']});
        return true;
    }
    // check the user id and api token match up:
    console.log('Hello');
});
app.listen(port);

如何让我的客户端在端口 81 上使用 HTTP 查询 API?

【问题讨论】:

    标签: axios


    【解决方案1】:

    CORS 是大多数浏览器中禁用跨域请求(即来自不同主机名的请求)的安全功能。要超越它,请通过 npm 在您的 Express 服务器上安装 cors 依赖项:

    npm install cors
    

    然后您需要通过cors() 函数将它添加到每个应用程序,添加到您希望允许其他域向其发出请求的每个{{httpMethod}}

    尝试像这样编辑您的代码:

    const express = require('express');
    const cors = require('cors')
    const app = express();
    const port = 81;
    
    app.get('/api/getAccountList', cors(), (req, res)=>{})
    

    【讨论】:

      【解决方案2】:

      您可以尝试将其添加到您的 Node.js 服务器吗?

      // Add headers
      app.use(function (req, res, next) {
      
          // Website you wish to allow to connect
          res.setHeader('Access-Control-Allow-Origin', 'http://localhost:81');
      
          // Request methods you wish to allow
          res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
      
          // Request headers you wish to allow
          res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
      
          // Set to true if you need the website to include cookies in the requests sent
          // to the API (e.g. in case you use sessions)
          res.setHeader('Access-Control-Allow-Credentials', true);
      
          // Pass to next layer of middleware
          next();
      });
      

      您可以尝试仅添加Access-Control-Allow-Origin 标头或根据您的需要修改其他标头。

      【讨论】:

      • 感谢您的回复,我知道这是一种方法。我宁愿告诉 axios (仅)在不同的端口上查询,而不是像这样生成一个 url。我喜欢如何将路径 (/api/getAccountList) 放在 axios get 中,它可以在我的本地开发、uat 和 live 中运行。您是否知道如何让 axios 不使用默认端口 80 并保持其他所有内容不变?
      • @NULLpointer,您可以在此处github.com/axios/axios/issues/187 和此处github.com/axios/axios/issues/1794 阅读有关该问题的信息。
      • 谢谢@webprogrammer - 看来我不是马可波罗。在阅读 github.com/axios/axios/issues/187 之后,我认为 Axios 也不会将其包含在他们的代码中。将尝试axios.defaults.port = 8080;,但也会查看 fetch() 是否允许我仅指定端口。
      【解决方案3】:

      为了实现所需的 CORS 保护并避免对服务器 FQDN/主机名进行硬编码,我在我的节点 api 服务器中使用了以下代码:

      const express = require('express');
      const app = express();
      const apiProviderPort = 81;
      const allowedApiConsumerPort = 80;
      
      app.use(function (req, res, next) {
        const host = req.get('host'); // NOTE host is the fqdn:port
        const hostSplit = host.split(':');
        var fqdn;
        if (hostSplit.length == 1) {
          // I am not sure this is needed, it will be if hostname is fqdn[:port]
          fqdn = host;
        } else if (hostSplit.length == 2) {
          fqdn = hostSplit[0];
        } else {
          console.log('Error the host contained multiple colons!');
        }
        console.log('protocol:',req.protocol,'host:',host,'fqdn:' + fqdn);
        // next line edited March 2020 - I changed + '//' + to + '//:' +
        // as the developer tools console showed
        // The 'Access-Control-Allow-Origin' header contains the invalid value 'http//localhost:3000'.
        const allowableOrigin = req.protocol + '//' + fqdn + ':' + allowedApiConsumerPort;
        console.log('allowableOrigin:',allowableOrigin)
        res.setHeader('Access-Control-Allow-Origin', allowableOrigin);
        next();
      });
      app.get('/api/userDocReportData/', (req, res) => {
        const userIdBy = req.params.userIdBy;
        const apiToken = req.params.apiToken;
      
        if (!(userIdBy && apiToken)) {
          res.status(200).json({errors:['Missing credentials']});
          return true;
        }
        // check the user id and api token match up:
        // ...
        // get your payload etc
        res.status(200).json({errors:false,payload:{} });
      });
      app.listen(apiProviderPort);
      

      我增强了上面的@webprogrammers 答案,因为我想要可以在任何环境(localhost;test.example.com,live.example.com 等)中工作的代码

      【讨论】:

        【解决方案4】:

        在客户端,为了让 Axios 从端口 81 获取与运行 javascript 相同的主机上的 GET:

        import axios from 'axios';
        //...
        //...
        axios.defaults.baseURL = window.location.protocol + "//" + window.location.hostname + ":81";
        const result = await axios('/your/endpoint');
        //...
        //...
        

        【讨论】:

          猜你喜欢
          • 2021-11-03
          • 2020-07-08
          • 1970-01-01
          • 2021-11-27
          • 2021-05-03
          • 1970-01-01
          • 2014-03-09
          • 1970-01-01
          • 2019-10-30
          相关资源
          最近更新 更多