为啥我的微 API 没有响应体?

Posted

技术标签:

【中文标题】为啥我的微 API 没有响应体?【英文标题】:Why my micro-API does not have response body?为什么我的微 API 没有响应体? 【发布时间】:2021-11-08 20:12:13 【问题描述】:

对于我的小型 javascript 应用程序,我使用 CGI 编写了服务器端 API 函数。

我把它做得很简单,完整的示例脚本如下所示:

#!/usr/bin/env perl

use strict; use warnings; use 5.014; 

use CGI;
use JSON;
use Data::Dumper;

my $q = new CGI;
my %p = $q->Vars;

_api_response();

sub _api_response 
  my ( $error ) = @_;
  my $res;

  my $status = 200;
  my $type = 'application/json';
  my $charset = 'utf-8';

  if ( $error ) 
    $status = 500;
    $res->data = 
      status => 500,
    ;
    $res->error = 
        error => 'failure',
        message => $error,
        detail => Dumper \%p,
    ;
   else 
    $res->data = 
      status => 200,
    ;
  

  print $q->header( 
    -status   => $status, 
    -type     => $type,
    -charset  => $charset,
  );

  my $body = encode_json( $res );
  print $body;

当我使用 fetch 从 JS 脚本调用它时,它没有得到响应体。如果我从开发者工具/网络检查,它也没有响应正文。如果我在浏览器中输入相同的 URL,它会显示 JSON 正文。如果我使用curl 作为

curl -v 'https://example.com/my_api?api=1;test=2;id=32'

响应似乎也有正确的正文:

< HTTP/2 200 
< date: Mon, 13 Sep 2021 14:04:42 GMT
< server: Apache/2.4.25 (Debian)
< set-cookie: example=80b7b276.5cbe0f250c6c7; path=/; expires=Thu, 08-Sep-22 14:04:42 GMT
< cache-control: max-age=0, no-store
< content-type: application/json; charset=utf-8
< 
* Connection #0 to host example.com left intact
"data":"status":200

为什么fetch 不将其视为一个身体?

为了完整起见,我还包括了 JS 部分:

async function saveData(url = '', data = ) 
  const response = await fetch(url, 
    method: 'GET', 
    mode: 'no-cors', 
    cache: 'no-cache', 
    credentials: 'omit',
    headers: 
      'Content-Type': 'application/json'
    ,
    redirect: 'follow', 
    referrerPolicy: 'no-referrer', 
  );
  console.log(response); // body is null
  return response.json(); 

使用函数为:

saveData('https://example.com/my_api?api=1;test=2;id=32',  answer: 42 )
  .then(data => 
    console.log(data);
  )
  .catch( error => 
    console.error( error );
  );

在控制台我看到错误:

SyntaxError: Unexpected end of input

此错误的一个可能原因是空 JSON 字符串。

【问题讨论】:

为什么fetch 中有content-type 标头?该标头指定请求正文的内容类型,但没有请求正文,因为它是 GET 请求。为了向服务器发出信号,您应该使用Accept 标头接受什么样的内容。另请注意,您没有在 curl 命令中发送此标头,因此此标头实际上可能是问题所在。 @SteffenUllrich content-type 显然是不必要的,但忽略它并没有改变。 你在 Perl 端做过调试吗?您在服务器日志中看到了什么? 你打电话给_api_response() 没有任何参数。 _api_response(@args) 需要一些参数,如果没有提供参数,那么你最终会得到 print $q-&gt;header(...)print $body 其中 body 是 json status =&gt; 200 (正是来自 Web 浏览器的请求接收)。看起来您的问题出在 JavaScript 中,出于调试目的添加 Perl 代码验证块,它将接收到的数据转储到文件中以研究可能导致问题的原因。 我可以用您显示的代码重现您的问题。 【参考方案1】:

我能够重现您的问题,然后我能够解决它。

这是一个 CORS 问题。前后端都需要开启CORS。

在前端,您需要在页面的&lt;head&gt; 中使用元标记设置内容安全策略:

<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval' http://localhost">

(不要忘记将localhost 更改为您的真实域名。)

在后面你需要添加 CORs 标题:

  print $q->header( 
    -status   => $status, 
    -type     => $type,
    -charset  => $charset,
    -access_control_allow_origin => '*', # <-- add this line
  );

附带说明,您传递给fetch 的任何设置都不是必需的。而且由于您正在等待响应,然后无论如何都返回另一个承诺,因此实际上没有理由让它成为一个异步函数。

在您准备好使用未使用的 data 参数做某事之前,以下代码就足够了:

function saveData(url = '', data = ) 
    return fetch(url).then(response=>response.json()); 

【讨论】:

【参考方案2】:

你也必须await response.json()

试试return await response.json();,而不是return response.json();

【讨论】:

我不完全按照您的解决方案。 async 函数应该返回 PromisesaveData 。我看不出在这里使用await 的理由(而且它不会改变结果)。 他们正在等待一个承诺然后返回另一个承诺,这有点奇怪,但这不是问题。如果您等待响应,那么代码将在稍后调用 then 时中断。

以上是关于为啥我的微 API 没有响应体?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能用我的 api 响应更新我的状态?数据是一个对象数组

为啥数组响应没有使用 PHP MySQL API 进入 JSON

为啥我的轮播滑块中的图像没有响应?

为啥我的获取帖子不起作用它没有响应?

为啥我的 instanceof 运算符没有响应 true?

为啥我的 UIView 在重新加载后没有响应?