通过nginx反向代理.net Soap Web Service 踩坑记

今天系统上线一个需要对一个原有老系统做一些安全防范,发现很多老旧的传统Soap Web Servcie对公网开放访问,自然想到用白名单对调用方加以限制。这里自然想到采用nginx做为反向代理服务器转发请求到iis上,于是便有了如下配置。

    server { 
        listen 8080;
        location / {
            proxy_pass http://127.0.0.1:8090;
            client_max_body_size 1024m;
            proxy_connect_timeout 3000;
            proxy_next_upstream_timeout 3000;
            proxy_read_timeout 3000;
            proxy_send_timeout 3000;
    }
    if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") 
    {
        set $year $1;
        set $month $2;
        set $day $3;
    }
    access_log  logs/$year-$month-$day-8080.xxx.com-access.log main;
}

这里对原先在8090 端口上运行的服务转给8080,对外网可以访问这样以后可以增加白名单等操作。

完成修改后 访问 http://external-ip:8080/test.asmx 顺利看到了测试界面于是感觉已经完成了配置,但是同事测试了一个接口地址,发现了特别神奇的问题如访问:
http://external-ip:8080/test.asmx?op=GetCBInfo 输入测试参数则在浏览器中发现请求被转发到了
http://127.0.0.1:8090/test.asmx?op=GetCBInfo 自然是请求不能访问的。
观察了下测试界面发现了不用于原来通过IIS直接访问,Soap web 服务的Host头似乎发生了变化,变成了127.0.0。1猜测是.net soap servie是根据访问的host头进行的host的设置的,而IIS直接访问就是外网ip或者域名,而进过nginx转发,则实践访问的host确实没有了外网ip了。于是修改为如下配置。

    
    server { 
        listen 8080;
        location / {
                proxy_pass http://webservie;
                client_max_body_size 1024m;
                proxy_connect_timeout 3000;
                proxy_next_upstream_timeout 3000;
                proxy_read_timeout 3000;
                proxy_send_timeout 3000;
                proxy_set_header   Host               $host:$server_port;
                proxy_set_header   X-Real-IP          $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Real-IP $remote_addr;
}
    if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") 
    {
        set $year $1;
        set $month $2;
        set $day $3;
    }
    access_log  logs/$year-$month-$day-8080.xxx.com-access.log main;
}

重新加载nginx配置后,发现请求转发的地址确实对了,但是端口不对,为8089内网的端口,于是只有查找更多的文档,发现了如下两行配置

    sub_filter   http://external-ip:8090/  http://expternal-ip:8080/;
     sub_filter '<soap:address location="http://extenal-ip:8090/' '<soap:address location="http://extenal-ip:8080/';
       sub_filter_once   off;

加入到location内,发现生效了转发有效,接口调用正常。

原理探究:
首先什么是sub_filter
官方文档说

The ngx_http_sub_module module is a filter that modifies a response by replacing one specified string by another.

也就是可以替换某些响应的信息,这里处理修改host防止发生跳转并将weburl中的8090设置为8080。猜测.net 服务那边拿了端口。
当然这些应该都可以通过Web Service 配置文件实现这里就不做进一步的探究了。

其中

sub_filter   http://external-ip:8090/  http://expternal-ip:8080/;

用于替换WSDL调试工具中post-form内的地址

sub_filter '<soap:address location="http://extenal-ip:8090/' '<soap:address location="http://extenal-ip:8080/';

用于替换wsdl中的不对的地址

----- 更新.........
发现确实是.net soap web service会带端口回来的问题。这里转载记录别人的探究
感谢CSDN博主「brainty」
原文链接:https://blog.csdn.net/ying83811/article/details/44198597
C#中使用webservice接口的时候,返给服务器的IP地址是带上了端口号的。但是有时候不能要那个端口(比如用nginx做了转发),就需要在服务端处理一下(处理内容就是后面的代码)。此外,需要在配置文件中web.config中的system.web中添加一些东西:

<webServices>

<protocols>

<add name="HttpGet"/>

<add name="HttpPost"/>

<add name="HttpSoap"/>

</protocols>

<soapExtensionReflectorTypes>

<add type="CommMethod.OuterPortReflector,CommMethod"/>

</soapExtensionReflectorTypes>

</webServices>

注:1.type内容是类名,包名。这一点和msdn上的那个人写的有些不同(有可能是版本的问题)(http://blogs.msdn.com/b/kaevans/archive/2005/11/16/493496.aspx)。

     2.如果没有protocols中的内容的话,有可能post和get请求不能被正确识别(未做过验证,只是在博客园上看见过类似问题)。

     3.stackoverflow源地址:http://stackoverflow.com/questions/1531448/asp-net-web-service-changes-port-on-invoke

————————————————

代码:

//-----------------------------------------------------------------------
// <copyright file="OuterPortReflector.cs" company="">
// * Copyright (C) 
// * version : 
// * author  : ying83811
// * FileName: OuterPortReflector.cs
// * history : created by ying83811 
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Description;

namespace Better517Na.KoreaProductInterface.CommMethod
{
    /// <summary>
    /// OuterPortReflector类 
    /// </summary>
    public class OuterPortReflector : SoapExtensionReflector
    {
        /// <summary>
        /// 重写ReflectMethod
        /// </summary>
        public override void ReflectMethod()
        {
        }

        /// <summary>
        /// 重写ReflectDescription
        /// </summary>
        public override void ReflectDescription()
        {

            //  为了说明问题,这里直接把端口号写死了,建议写在配置文件中
            string portNum = "8888";

            portNum = ":" + portNum;
            ServiceDescription description = ReflectionContext.ServiceDescription;
            foreach (Service service in description.Services)
            {
                foreach (Port port in service.Ports)
                {
                    foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
                    {
                        SoapAddressBinding binding = extension as SoapAddressBinding;
                        if (null != binding)
                        {
                            binding.Location = binding.Location.Replace(portNum, string.Empty);
                        }
                        else
                        {
                            HttpAddressBinding httpBinding = extension as HttpAddressBinding;
                            if (httpBinding != null)
                            {
                                httpBinding.Location = httpBinding.Location.Replace(portNum, string.Empty);
                            }
                            else
                            {
                                Soap12AddressBinding soap12Binding = extension as Soap12AddressBinding;
                                if (soap12Binding != null)
                                {
                                    soap12Binding.Location = soap12Binding.Location.Replace(portNum, string.Empty);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Lokie博客
请先登录后发表评论
  • 最新评论
  • 总共0条评论
  • 本博客使用免费开源的 laravel-bjyblog v5.5.1.1 搭建 © 2014-2018 lokie.wang 版权所有 ICP证:沪ICP备18016993号
  • 联系邮箱:kitche1985@hotmail.com