2010-12-07 39 views
9

Tôi có một webservice asp.net .asmx bản để xử lý yêu cầu từ một công cụ của bên thứ ba. Công cụ của bên thứ ba thực hiện yêu cầu POST http tới webservice để nhận thông tin người dùng. Tôi đang sử dụng IIS7asp.net xử lý webservice gzip nén yêu cầu

Chạy Fiddler với "Remove All Mã hoá" kiểm tra, tôi có thể thấy chức năng tất cả những gì gọi webservice và và đúng cách. Nếu tôi bỏ chọn "Remove All Encodings", cuộc gọi webservice sẽ thất bại với yêu cầu 400 Bad. Sự khác biệt mà tôi thấy là tiêu đề "Content-Encoding: gzip" đang được xóa bởi Fiddler và nội dung đang được giải nén.

Vì vậy, khi header Content-Encoding được lấy ra và nội dung được giải nén, chức năng webservice của tôi một cách hoàn hảo. Khi tiêu đề có mặt và nội dung được nén, webservice không thành công.

Làm thế nào tôi có thể một trong hai:

  1. Cấu hình webservice của tôi để nói với khách hàng rằng nó sẽ không chấp nhận yêu cầu nén (và hy vọng rằng công cụ của bên thứ ba tôn trọng đó)
  2. Decompress nội dung sớm trong asp.net xử lý
  3. Sửa webservice của tôi để làm việc với dữ liệu nén

cập nhật: để được rõ ràng, tôi không cần để định cấu hình mã hóa gzip trong Phản hồi, tôi cần xử lý Yêu cầu tới dịch vụ web của tôi được mã hóa gzip.

Cập nhật 2: Công cụ của bên thứ ba là plugin Salesforce.com Outlook. Vì vậy, tôi không có quyền truy cập để sửa đổi nó và nó được sử dụng bởi nhiều công ty khác mà không gặp rắc rối. Đó phải là điều tôi đang làm (hoặc không làm)

Cập nhật 3: Tôi tìm thấy một bài đăng here nói rằng IIS không hỗ trợ yêu cầu POST đến với dữ liệu nén, nó chỉ hỗ trợ phản hồi nén. Điều này có đúng không?

Trả lời

1

Tôi đã tìm thấy câu trả lời một phần here.

class DecompressStream : Stream 
{ 
    ... 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     GZipStream test = new GZipStream(_sink, CompressionMode.Decompress); 

     int c = test.Read(buffer, offset, count); 

     return c; 
    } 

    ... 
} 

tôi sau đó có thể chỉ định các bộ lọc trên đối tượng yêu cầu như thế này:

void Application_BeginRequest(object sender, EventArgs e) 
    { 
     string contentEncoding = Request.Headers["Content-Encoding"]; 
     Stream prevCompressedStream = Request.Filter; 

     if(contentEncoding == null || contentEncoding.Length == 0) 
      return; 

     contentEncoding = contentEncoding.ToLower(); 

     if(contentEncoding.Contains("gzip")) 
     { 
      Request.Filter = new DecompressStream(Request.Filter); 
     } 
    } 

tôi nói phần câu trả lời bởi vì mặc dù bây giờ tôi có thể xử lý các yêu cầu gửi đến, câu trả lời là nhận được một " Nội dung Mã hóa: gzip "tiêu đề mặc dù phản ứng không được mã hóa. Tôi có thể xác minh trong Fiddler rằng nội dung không được mã hóa.

Nếu tôi mã hóa phản hồi, ứng dụng khách cho dịch vụ web không thành công. Dường như mặc dù nó đang gửi "Accept-Encoding: gzip", nó không thực sự chấp nhận phản hồi nén gzip. Tôi có thể xác minh trong Fiddler rằng phản ứng được nén và Fiddler sẽ giải nén nó thành công.

Vì vậy, hiện tại tôi đang cố gắng lấy tiêu đề "Nội dung Mã hóa: gzip" bị loại bỏ khỏi phản hồi. Tôi đã xóa tất cả các tham chiếu mà tôi có thể tìm thấy để nén từ ứng dụng, web.config và IIS.

+0

Tôi chưa làm việc với các dịch vụ web ASP Web Services (.asmx) trong một vài năm, nhưng bạn không thể truy cập vào các tiêu đề phản hồi bằng HttpContext.Current.Response.Headers? –

+0

@ Florin, bạn đúng. Tôi đã có thể loại bỏ Header vi phạm trong chức năng PostRequestHandlerExecute VÀ loại bỏ tiêu đề Accelpt-Encoding khỏi yêu cầu đến trong hàm BeginRequest. Đã phải làm cả hai để làm cho nó hoạt động. – Geoff

1

Nén GZIP là chức năng của máy chủ.

Nếu bạn đang sử dụng IIS6, tham khảo ý kiến ​​this link.

Nếu bạn đang sử dụng IIS7, bạn có thể sử dụng để vô hiệu hóa ISAPI_Rewrite gzip. Xem this link. Điều đó nói rằng, vì gzip là một chức năng của IIS, bạn thực sự không cần phải làm bất cứ điều gì "đặc biệt" để làm cho nó hoạt động với một dịch vụ web (IIS nên xử lý các yêu cầu giải nén và nén). Hy vọng rằng thông tin này sẽ giúp bạn tiếp tục xuống đường để khắc phục sự cố và giải quyết vấn đề.

+0

Cảm ơn, nhưng cho đến xa điều này không giúp được gì. Tôi có thể tắt nén trong IIS7 bằng cách bỏ chọn các hộp trong cài đặt cấu hình, nhưng một lần nữa, điều này dường như chỉ ảnh hưởng đến Phản hồi từ máy chủ. Tôi cần phải đối phó với một yêu cầu Để máy chủ được nén. – Geoff

+0

Dưới đây là cuộc hội thoại máy khách/máy chủ gzip thường hoạt động: http://www.websiteoptimization.com/speed/tweak/compress/ –

+0

Có thể công cụ của bên thứ ba của bạn không hoạt động tốt. –

2

Vì dịch vụ của bên thứ ba chỉ gửi cho bạn một POST, tôi không nghĩ rằng có thể yêu cầu họ không gửi được nén.

Bạn có thể thử để ghi đè GetWebRequest và giải nén nó trên đường trong

public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol 

{ 
protected override WebRequest GetWebRequest(Uri uri) 
{ 
    base.GetWebRequest(uri);request.AutomaticDecompression = System.Net.DecompressionMethods.GZip; 
    return request; 
} 
} 
+0

Cảm ơn. Thật không may, yêu cầu không bao giờ làm cho nó xa này. Câu trả lời của bạn đã dẫn tôi tìm ra lời gọi cuối cùng trong chuỗi thành công là PreRequestHandlerExecute và điều đó đã khiến tôi cố gắng Lọc đầu vào như được mô tả trong câu trả lời của tôi. – Geoff

1

Tôi không chắc chắn rằng IIS hỗ trợ giải nén yêu cầu gửi đến, vì vậy đây có thể phải được thực hiện tiếp tục xuống đường ống.

Câu trả lời của Shiraz có khả năng làm việc và đó sẽ là điều đầu tiên tôi thử.

Nếu điều đó không hoạt động, bạn có thể cân nhắc việc chuyển dịch vụ .asmx của máy chủ thành WCF, trong khi khó thiết lập hơn một chút thì cũng linh hoạt hơn.

Về phía WCF, có hai điều tôi có thể đề xuất. Việc đầu tiên là khá dễ dàng để thực hiện và được dựa trên thiết lập các đối tượng WebRequest được sử dụng bởi WCF để tự động chấp nhận nén. Bạn có thể tìm thấy chi tiết here. Đây là WCF tương đương với giải pháp được đề xuất bởi Shiraz.

Thứ hai phức tạp hơn, vì nó liên quan đến việc tạo Bộ mã hóa thông báo tùy chỉnh, nhưng nếu không có phương pháp nào ở trên hoạt động, điều này sẽ giải quyết được vấn đề. Tạo bộ mã hóa nén tin nhắn được mô tả here. Bạn cũng có thể muốn kiểm tra câu trả lời trong here trình bày cấu hình mẫu cho bộ mã hóa thư.

Vui lòng cho tôi biết nếu điều này có hữu ích hay không nếu bạn cần thêm trợ giúp.

5

Kỹ thuật đơn giản nhất là tạo HttpModule để thay thế bộ lọc yêu cầu. Nó có thể tái sử dụng nhiều hơn và tránh có Global.asax. Cũng không cần phải tạo một lớp dòng giải nén mới vì GZipStream đã sẵn sàng cho điều đó. Đây là mã đầy đủ, mà còn loại bỏ các Content-Encoding: gzip đó là không cần thiết nữa:

public class GZipRequestDecompressingModule : IHttpModule 
{ 
    public void Init(HttpApplication context) 
    { 
     context.BeginRequest += (sender, e) => 
     { 
      var request = (sender as HttpApplication).Request; 

      string contentEncoding = request.Headers["Content-Encoding"]; 

      if (string.Equals(contentEncoding, "gzip", 
       StringComparison.OrdinalIgnoreCase)) 
      { 
       request.Filter = new GZipStream(request.Filter, 
        CompressionMode.Decompress); 
       request.Headers.Remove("Content-Encoding"); 
      } 
     }; 
    } 
    public void Dispose() 
    { 
    } 
} 

Để kích hoạt mô-đun này, thêm phần sau vào web.config của bạn:

<system.webServer> 
    <modules runAllManagedModulesForAllRequests="true"> 
     <add name="AnyUniqueName" 
      type="YourNamespace.GZipRequestDecompressingModule, YourAssembly" 
      preCondition="integratedMode" /> 
    </modules> 
</system.webServer> 
+0

Chỉ có thể kích hoạt mô-đun này trên các đường dẫn nhất định, để tránh bất kỳ tác dụng phụ tiềm ẩn nào? Tức là chỉ kích hoạt nó cho các tập tin ASMX? – NickG

+1

Chắc chắn, sử dụng [phần tử vị trí] (http://msdn.microsoft.com/en-us/library/b6x6shw7 (v = vs.100) .aspx) trong web.config nơi bạn chỉ định thuộc tính 'đường dẫn' là cần thiết. – Mart

+0

BTW: thay vì string.Equals (contentEncoding, "gzip", StringComparison.OrdinalIgnoreCase), bạn có thể làm contentEncoding.ToLower() == "gzip" nhanh hơn rất nhiều để gõ :) – NickG

Các vấn đề liên quan