2013-07-31 33 views
9

Trong đoạn code dưới đây tôi không thể hiểu tại sao req.pipe (res) không hoạt động, và chưa ném một lỗi. Một linh cảm nói với tôi đó là do hành vi asynch của nodejs, nhưng đây là một trường hợp rất đơn giản mà không cần gọi lại.NodeJS - Làm thế nào để dòng yêu cầu cơ thể mà không đệm

Tôi đang thiếu gì?

http.createServer(function (req, res) { 

    res.writeHead(200, { 'Content-Type': 'text/plain' }); 

    res.write('Echo service: \nUrl: ' + req.url); 
    res.write('\nHeaders:\n' + JSON.stringify(req.headers, true, 2)); 

    res.write('\nBody:\n'); 

    req.pipe(res); // does not work 

    res.end(); 

}).listen(8000); 

Đây là curl:

➜ ldap-auth-gateway git:(master) ✗ curl -v -X POST --data "test.payload" --header "Cookie: token=12345678" --header "Content-Type:text/plain" localhost:9002 

Dưới đây là kết xuất debug (xem cơ thể đã được tải lên):

About to connect() to localhost port 9002 (#0) 
    Trying 127.0.0.1... 
    connected 
    Connected to localhost (127.0.0.1) port 9002 (#0) 
    POST/HTTP/1.1 
    User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8x zlib/1.2.5 
    Host: localhost:9002 
    Accept: */* 
    Cookie: token=12345678 
    Content-Type:text/plain 
    Content-Length: 243360 
    Expect: 100-continue 

    HTTP/1.1 100 Continue 
    HTTP/1.1 200 OK 
    Content-Type: text/plain 
    Date: Sun, 04 Aug 2013 17:12:39 GMT 
    Connection: keep-alive 
    Transfer-Encoding: chunked 

Và các dịch vụ đáp ứng mà không lặp lại cơ thể yêu cầu:

Echo service: 
Url:/
Headers: 
{ 
    "user-agent": "curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8x zlib/1.2.5", 
    "host": "localhost:9002", 
    "accept": "*/*", 
    "cookie": "token=12345678", 
    "content-type": "text/plain", 
    "content-length": "243360", 
    "expect": "100-continue" 
} 

... và gỡ lỗi curl cuối cùng là

Body: 
Connection #0 to host localhost left intact 
Closing connection #0 

Ngoài ra, khi tôi kiểm tra căng thẳng với thân yêu cầu lớn, tôi gặp lỗi EPIPE. Làm thế nào tôi có thể tránh điều này?

- CHỈNH SỬA: Qua thử và sai, tôi đã làm việc này và nó vẫn chỉ là vấn đề về thời gian. Mặc dù nó vẫn còn lạ, vì thời gian chờ làm cho tải trọng phải được trả lại, nhưng thời gian chờ không phải là minded. Nói cách khác cho dù tôi đặt thời gian chờ là 5 giây hoặc 500 giây, tải trọng được truyền lại đúng theo yêu cầu và kết nối bị chấm dứt.

Đây là chỉnh sửa:

http.createServer(function (req, res) { 

    try { 
     res.writeHead(200, { 'Content-Type': 'text/plain' }); 
     res.write('Echo service: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); 
     res.write('\nBody:"\n'); 
     req.pipe(res); 
    } catch(ex) { 
     console.log(ex); 
     // how to change response code to error here? since headers have already been written? 
    } finally { 
     setTimeout((function() { 
     res.end(); 
     }), 500000); 
    } 

}).listen(TARGET_SERVER.port); 

?

+0

Lưu ý rằng bạn sẽ thấy rằng yêu cầu được gửi đến 9002. Đây là proxy ngược (nút đơn giản-http-proxy đến 8000, mục tiêu). Việc đưa mục tiêu trực tiếp mang lại kết quả tương tự. –

Trả lời

6

Yêu cầu về ống để quay lại. Req là dòng có thể đọc được và phản ứng là một stream.It ghi nên làm việc

http.createServer(function (req, res) { 

     res.writeHead(200, { 'Content-Type': 'text/plain' });  
     res.write('Echo service: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); 

     // pipe request body directly into the response body 
     req.pipe(res);  

    }).listen(9002); 
+0

Điều này sẽ hoạt động ... * đôi khi * ... có điều gì đó không đồng bộ về cuộc gọi đường ống. Cỗ máy càng nhanh thì điều này càng không hiệu quả chút nào. Tôi có thể làm cho nó hoạt động bằng cách chờ trước khi gọi res.end(). Tiền thưởng là cho bất cứ ai có thể giải thích lý do tại sao tôi đã có thể khắc phục vấn đề này bằng cách thêm một giấc ngủ. (xem phần chỉnh sửa của tôi ở cuối câu hỏi) –

+1

Cuộc gọi PIPE sẽ xử lý việc gọi lại.thêm khi luồng req gọi gần/kết thúc. Không cần phải gọi lại res.end sau piping.Bạn thử mã trên mà không dùng res.end()? – Chandu

+0

Lý do mã của bạn hoạt động sau khi thêm ngủ (không phải là thuật ngữ đúng trong nodejs :-)) là đường ống thực sự nhận được thời gian đóng luồng phản hồi sau khi luồng lại kết thúc.res.end() trong settimeout chỉ đơn thuần là đóng luồng đã đóng . – Chandu

5

Vì vậy, đầu tiên, có vẻ như curl của bạn đã tắt, tên tập tin của dữ liệu gửi nên được bắt đầu bằng @as shown here. Bạn sẽ chỉ đăng tên tập tin nếu không.

Bên cạnh đó, Chandu đúng khi nói rằng cuộc gọi đến res.end() là vấn đề ở đây.

Vì IO không đồng bộ trong nút, khi bạn phát hành lệnh .pipe, điều khiển sẽ ngay lập tức được trả về ngữ cảnh hiện tại, trong khi đường ống hoạt động ở chế độ nền. Khi bạn gọi tới số res.end(), bạn đóng luồng, preventing any more data to be written.

Giải pháp ở đây là để cho .pipe kết thúc luồng, which is the default.

Tôi tưởng tượng rằng thời gian được phát bởi vì trên các máy khác nhau và kích thước dữ liệu khác nhau, IO không đồng bộ về mặt lý thuyết có thể hoàn thành (IO nhanh của tập dữ liệu nhỏ) trước khi sự kiện kết thúc trên luồng ghi được xử lý hoàn toàn.

Tôi muốn giới thiệu this blog post cho một số ngữ cảnh khác.

+0

Điều đó có ý nghĩa hoàn hảo. Cảm ơn lời giải thích. –

+0

Re the curl post. Đó là cố ý như tôi đã làm cả hai .. đã tắt @ để kiểm tra chỉ là một vài ký tự so với trọng tải tương đối lớn chứa trong tập tin. –

+0

Vì vậy, nếu tôi có thể hiểu được hành vi hết thời gian "buồn cười" ... ống sẽ mất 500 ms và sau đó đóng kết nối. Thời gian chờ vẫn xảy ra (ngay cả khi đặt 500 giây vào tương lai), nhưng chỉ đơn giản là không làm bất cứ điều gì khi res.close được gọi, kể từ khi res đã được đóng lại. Tôi mong chờ một số lỗi được báo cáo. –

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