当前位置: 首页 > news >正文

php调用soap, 报错 failed to load external entity‘http://xxxxxxxx?wsdl‘ 解决方法

先说下环境,非当前环境参考思路
  • 服务器 centos 6
  • php版本 5.5.39
  • 调用java写的soap服务器
  • 开启soap缓存
  • 出现的问题是, 运行一段时间后就会随机报异常
 PHP Fatal error:  SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://xxxxxxxx?wsdl' : failed to load external entity'http://xxxxxxxx?wsdl'
解决方法
  1. php 代码中soap调用之前加上libxml_disable_entity_loader,如下情况。
libxml_disable_entity_loader(false);
$soap = new SoapClient(“http://xxx?wsdl”);
  1. 增加系统配置: /etc/sysctl.conf
vim /etc/sysctl.conf# 允许重用处于 TIME-WAIT 状态的 TCP 连接net.ipv4.tcp_tw_reuse = 1# 设置 FIN-WAIT-2 状态连接的超时时间为 30 秒net.ipv4.tcp_fin_timeout = 30sudo sysctl -p


排查方法

  1. wsdl 是协议文档,建立连接的时候需要去读取xml。而php源码中是这样描述的:
xmlDocPtr soap_xmlParseFile(const char *filename TSRMLS_DC)
{old_allow_url_fopen = PG(allow_url_fopen);PG(allow_url_fopen) = 1;ctxt = xmlCreateFileParserCtxt(filename);PG(allow_url_fopen) = old_allow_url_fopen;if (ctxt) {zend_bool old;ctxt->keepBlanks = 0;ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;ctxt->sax->comment = soap_Comment;ctxt->sax->warning = NULL;ctxt->sax->error = NULL;
#if LIBXML_VERSION >= 20703ctxt->options |= XML_PARSE_HUGE;
#endifold = php_libxml_disable_entity_loader(1 TSRMLS_CC);xmlParseDocument(ctxt);php_libxml_disable_entity_loader(old TSRMLS_CC);if (ctxt->wellFormed) {ret = ctxt->myDoc;if (ret->URL == NULL && ctxt->directory != NULL) {ret->URL = xmlCharStrdup(ctxt->directory);}} else {ret = NULL;xmlFreeDoc(ctxt->myDoc);ctxt->myDoc = NULL;}xmlFreeParserCtxt(ctxt);} else {ret = NULL;}

PG(allow_url_fopen) = 1; 这段代码必须允许读取远程资源。
xmlCreateFileParserCtxt 默认情况下只允许打开本地的xml。以上配合使用才可以读取远程xml。
原理是php的流封装器(Stream Wrappers)机制,它允许 PHP 使用统一的接口处理不同类型的流(如文件、HTTP、FTP 等)。
而又因为以下3行代码,明确了是不允许加载外部xml的。因此可以推测在xmlCreateFileParserCtxt 函数的时候要设置允许加载外部xml

old = php_libxml_disable_entity_loader(1 TSRMLS_CC);
xmlParseDocument(ctxt);
php_libxml_disable_entity_loader(old TSRMLS_CC);

验证推测, 采用以下php代码, 强制禁用远程xml,且不允许缓存

<?php
libxml_disable_entity_loader(true);
try {$crmapiurl='http://xxx?wsdl';$soap = new SoapClient($crmapiurl, ['trace' => true,'cache_wsdl' =>  WSDL_CACHE_NONE,]);
} catch (SoapFault $fault) {var_dump($fault);
}

测试结果直接报错

 PHP Fatal error:  SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://xxxxxxxx?wsdl' : failed to load external entity'http://xxxxxxxx?wsdl'

而把libxml_disable_entity_loader(false); 就可以正常运行
由此得出结论, soap使用wsdl的时候, 一定要加libxml_disable_entity_loader(false);
顺便说一句, 没有设置这个却还能正常运行的原因是读取了缓存

  1. 错误原因描述:在fpm运行一段时间后, 开始报之前的错误, 但是重启fpm就恢复正常
    • 推测重启后进程结束,说明资源被释放
    • 而运行一段时间后又开始以上报错,反复如此
    • php代码中, soap是作为客户端去访问java服务器
      以上三点可以得出,当fpm把请求执行完之后,soap的相关资源是没有被释放的,然后重复请求会建立多个TCP请求,随着时间增加,服务器的资源被消耗完,解决方式就是使用 net.ipv4.tcp_tw_reuse 进行tcp的复用,减少链接就可以
http://www.lryc.cn/news/383846.html

相关文章:

  • ts可选参数
  • day41--Redis(三)高级篇之最佳实践
  • PDF 生成(4)— 目录页
  • 黑盒测试用例的四种设计方法
  • GIT重新提交-恢复到暂存状态
  • 半藏酒商业模式解读,半藏酱酒营销案例,半藏总院分院招商模式
  • 从云原生视角看 AI 原生应用架构的实践
  • 浅学JVM
  • 算法训练营64-图论-深度优先优先搜索(dfs)-广度优先搜索(bfs)
  • kotlin函数
  • 深入理解计算机系统 CSAPP 家庭作业7.12
  • Batch脚本中的环境变量沙盒:setlocal与endlocal全解析
  • AI引领创意潮流:高效生成图片,参考图助力,一键保存到指定文件夹
  • ADOP带你了解:数据中心的高速互联解决方案
  • 使用SpringBoot整合Servlet
  • vue引入eachrts
  • c++ 智能指针实战分析
  • 3D Web轻量引擎HOOPS Web Platform赋能AEC行业数字化,高效渲染与多格式支持!
  • 学术英语写作为什么会成为留学生的压力?
  • docker 安装达梦8
  • npm常用命令大全(非常详细)
  • 东西方文化与管理探讨汉捷咨询汉捷咨询
  • 行业案例 | 智能终端设备的数据基础从哪儿来?
  • 《Windows API每日一练》6.1 鼠标基础知识
  • 闹大了!OpenAI 宣布终止提供API服务
  • java里的空接口实现它有什么用?
  • Spring的jar包下载(最新版6.0版本)
  • 解决Java中数据库连接泄露的技术
  • 网页视频录制,分享3种好方法
  • LeNet网络的实现