이 글은 주로 Node를 사용하여 특정 참고 가치를 지닌 정적 파일 서비스를 소개합니다. 필요한 친구들이 참고할 수 있습니다.
정적 파일 서버 만들기
루트 디렉터리
가 있습니다. 따라서 생성하려는 서버에서 정적 파일 서버의 루트 디렉터리 역할을 할 루트 변수를 정의해야 합니다. var http = require('http') var join = require('path').join var fs = require('fs') var root = __dirname
__dirname은 Node의 마법 변수이며 해당 값 is 파일이 있는 디렉터리의 경로입니다. 이 예에서 서버는 이 스크립트가 있는 디렉터리를 정적 파일의 루트 디렉터리로 사용합니다. 根目录
,也就是提供文件服务的基础目录。所以我们要在即将创建的服务器上定义一个root变量,它将作为我们这个静态文件服务器的根目录:
var server = http.createServer(function(req, res){ let path = join(root, req.url) let stream = fs.createReadStream(path) stream.on('data', function(chunk){ res.write(chunk) }) stream.on('end', function(){ res.end() }) }) server.listen(3000)
__dirname 在Node中是一个神奇的变量,它的值是该文件所在目录的路径。在本例中,服务器会将这个脚本所在的目录作为静态文件的根目录。
有了文件的路径,还需要传输文件的内容。
这可以用fs.ReadStream
完成,它是Node中Stream类之一。成功调用 fs.createReadStream() 会返回一个新的 fs.ReadStream 对象。
下面的代码实现了一个简单但功能完备的文件服务器。
var server = http.createServer(function(req, res){ let path = join(root, req.url) let stream = fs.createReadStream(path) stream.pipe(res) }) server.listen(3000)
这个文件服务器大体能用,但还有很多细节需要考虑。接下来我们要优化数据的传输,同时也精简一下服务器的代码。
虽然上面的代码看上去还不错,但Node还提供了更高级的实现机制:Stream.pipe()
。用这个方法可以极大简化服务器的代码。 优化后代码如下:
ReadableStream.pipe(WritableStream)
这种写法,是不是更简单,更清晰了呢?
流是Node中很重要的一个概念,你可以把Node中的管道想象成水管,如果你想让某个源头(比如热水器)流出来的水流到一个目的地(比如厨房的水龙头),可以在中间加一个管道把它们连起来,这样水就会顺着管道从源头流到目的地。
Node中的管道也是这样,但其中流动的不是水,而是来自源头(即ReadableStream
)的数据,管道可以让它们“流动”到某个目的地(即WritableStream
)。你可以用pipe方法把管道连起来:
let readStream = fs.createReadStream('./original.txt') let writeStream = fs.createWriteStream('./copy.txt') readStream.pipe(writeStream)
读取一个文件(ReadableStream)并把其中的内容写到另一个文件中(WritableStream)用的就是管道:
req.pipe(fs.createWriteStream('./req-body.txt'))
所有ReadableStream都能接入任何一个WritableStream。比如HTTP请求(req)对
象就是ReadableStream,你可以让其中的内容流动到文件中:
stream.on('error', function(err){ res.statusCode = 500 res.end('服务器内部错误') })
现在我们来运行上面的代码,我们在根目录下放一张图片,比如peiqi.jpg。
在浏览器中输入http://127.0.0.1:3000/peiqi.jpg
,发现可爱的peiqi已经出现在你的面前了。peiqi.jpg
被当作响应主体从http服务器送到了客户端(浏览器)。
虽然已经品尝到了成功的滋味,但这个静态文件服务器还不够完整,因为它很容易出错。想象一下,如果用户不小心输入了一个并不存在的资源,比如abc.html,服务器就会马上崩掉。所以我们还得给这个文件服务器加上错误处理机制,让它足够健壮
。
在Node中,所有继承了EventEmitter的类都可能会发出error事件。为了监听错误,在fs.ReadStream上注册一个error事件处理器(比如下面这段代码),返回响应状态码500表明有服务器内部错误:
var server = http.createServer(function(req, res){ let path = join(root, req.url) fs.stat(path, function(err, stat) { if (err) { if ('ENOENT' == err.code) { res.statusCode = 404 res.end('Not Found') } else { res.statusCode = 500 res.end('服务器内部错误') } } else { // 有该文件 res.setHeader('Content-Length', stat.size) var stream = fs.createReadStream(path) stream.pipe(res) stream.on('error', function(err) { // 如果读取文件出错 res.statusCode = 500 res.end('服务器内部错误') }) } }) }) server.listen(3000)
我们可以用fs.stat()
来获取文件的相关信息,如果文件不存在,fs.stat()会在err.code中放入ENOENT
파일 경로와 함께 파일 내용도 함께 전송해야 합니다.
fs.ReadStream
을 사용하여 수행할 수 있습니다. fs.createReadStream()에 대한 성공적인 호출은 새로운 fs.ReadStream 객체를 반환합니다. 이 파일 서버는 일반적으로 작동하지만 고려해야 할 세부 사항이 많습니다. 다음으로 데이터 전송을 최적화하고 서버 코드를 간소화해야 합니다.
Stream.pipe(). 이 방법을 사용하면 서버 코드를 크게 단순화할 수 있습니다. 최적화된 코드는 다음과 같습니다.
이렇게 작성하는 방법이 더 간단하고 명확할까요?
Flow는 Node에서 매우 중요한 개념입니다. 특정 소스(예: 물 파이프)를 원할 경우 Node의 파이프를 생각할 수 있습니다. 온수기) ) 물이 목적지(예: 주방 수도꼭지)로 흘러나갑니다. 중간에 파이프를 추가하여 연결하면 물이 소스에서 목적지까지 파이프를 따라 흐를 수 있습니다.
Node의 파이프도 마찬가지지만 그 안에 흐르는 것은 물이 아니라 소스(예:ReadableStream
)의 데이터입니다. 특정 대상(예: WritableStream
) 파이프 방법을 사용하여 파이프를 연결할 수 있습니다: rrreee
파일을 읽고(ReadableStream) 내용을 다른 파일에 쓰는 경우(WritableStream) 파이프를 사용합니다:rrreee All ReadableStreams 모든 WritableStream에 연결될 수 있습니다. 예를 들어, HTTP 요청(req) 객체 는 ReadableStream이며 콘텐츠가 파일로 흐르도록 할 수 있습니다.
rrreee
http://127.0.0.1:3000/peiqi.jpg
를 입력하면 귀여운 페이치가 눈앞에 나타난 것을 확인할 수 있습니다. peiqi.jpg
는 http 서버에서 클라이언트(브라우저)로 응답 본문으로 전송됩니다. #🎜🎜##🎜🎜##🎜🎜#성공을 맛봤지만 이 정적 파일 서버는 오류가 발생하기 쉬우므로 완전하지 않습니다. 사용자가 실수로 abc.html과 같이 존재하지 않는 리소스를 입력하면 서버가 즉시 중단된다고 상상해 보십시오. 따라서 우리는 이 파일 서버를 충분히 견고하게
만들기 위해 오류 처리 메커니즘을 추가해야 합니다. #🎜🎜##🎜🎜#서버 오류 처리#🎜🎜##🎜🎜#Node에서 EventEmitter를 상속하는 모든 클래스는 오류 이벤트를 발생시킬 수 있습니다. 오류를 모니터링하려면 fs.ReadStream에 오류 이벤트 핸들러(예: 다음 코드)를 등록하고 응답 상태 코드 500을 반환하여 내부 서버 오류를 나타냅니다. #🎜🎜#rrreee#🎜🎜# fs.stat로 구현됨 () 오류 처리#🎜🎜##🎜🎜#fs.stat()
를 사용하여 파일에 대한 관련 정보를 얻을 수 있습니다. 파일이 존재하지 않으면 fs.stat()가 해당 파일을 저장합니다. 응답으로 err.code ENOENT
에서 오류 코드 404를 반환하여 클라이언트에 파일을 찾을 수 없음을 나타낼 수 있습니다. fs.stat()가 다른 오류 코드를 반환하는 경우 일반 오류 코드 500을 반환할 수 있습니다. #🎜🎜#리팩터링된 코드는 다음과 같습니다. #🎜🎜#rrreee#🎜🎜#Note#🎜🎜##🎜🎜#이 섹션에서 구축된 파일 서버는 단순화된 버전입니다. 이를 프로덕션 환경에 적용하려면 입력의 유효성을 더욱 철저하게 확인하여 사용자가 열려고 하지 않은 디렉터리 탐색 공격을 통해 콘텐츠의 일부에 액세스하는 것을 방지해야 합니다. #🎜🎜##🎜🎜#Summary#🎜🎜##🎜🎜#이 글을 읽고 나면 당신은 똑똑하고 Node를 사용하여 정적 서버를 만드는 방법을 마스터했다고 믿습니다. 다음 기사에서는 그 방법을 소개하겠습니다. Node를 사용하여 사용자를 처리하려면 파일을 업로드하고 서버에 저장하세요. #🎜🎜##🎜🎜#위 내용은 모두의 학습에 도움이 되기를 바랍니다. 더 많은 관련 내용은 PHP 중국어 홈페이지를 주목해주세요! #🎜🎜##🎜🎜#관련 권장 사항: #🎜🎜##🎜🎜##🎜🎜#Node를 사용하여 파일 업로드 처리#🎜🎜##🎜🎜##🎜🎜#ES6 작성 방법을 사용하여 Redux 소스 코드의 일부 해석
위 내용은 Node로 정적 파일 제공의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!